剑指offer 第十一天

46.扑克牌顺子

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers.length < 5) return false;
        Arrays.sort(numbers);
        int zerosNum = 0;
        int needZeros = 0;
        for(int i = 0 ;i < 5;i++){
            if(numbers[i] == 0){
                zerosNum++;
            }else if(i+1<5){
                //如存在两数字相同,则一定不是顺子
                if(numbers[i+1] == numbers[i]) return false;
                needZeros += numbers[i+1] - numbers[i] -1;
            }
        }
        //此时大王个数超过四个,不符合题目要求
        if(zerosNum > 4) return false;
        if(zerosNum >= needZeros) return true;
        else return false;
    }
}

46.孩子们的游戏

n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人 继续从0开始报数。求胜利者的编号。(约瑟夫环问题)
解法一:使用数组模拟环

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n<0||m<1) return -1;
        int[] array = new int[n];
        int count=n,step=0,idx=-1;
        while(count>0){
            idx++;
            if(idx == n) idx=0;
            if(array[idx] == -1) continue;//如果是被标记过的则跳过
            step++;
            if(step == m){
                array[idx] = -1;
                count--;
                step=0;
            }
        }
        return idx;
    }
}

解法二:使用ArrayList模拟环

import java.util.ArrayList;
public class Solution {
    public int LastRemaining_Solution(int n, int m){
        if(n<0||m<1) return -1;
        ArrayList<Integer> list = new ArrayList<>();
        for(int i = 0;i<n;i++)
            list.add(i);
        int idx = (m-1)%n;
        while(list.size()>1){
            list.remove(idx);
            idx = (idx+m-1)%list.size();
        }
        return list.get(0);
    }
}

47.求1+2+3+...+n

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

解题思路:(短路求值)

  1. 需利用逻辑与短路特性实现递归终止。
  2. 当n==0时,(n>0)&&((sum+=Sum_Solution(n-1))>0)只执行前面的判断,为false,然后直接返回0;
  3. 当n>0时,执行sum+=Sum_Solution(n-1),实现递归计算Sum_Solution(n)。
public class Solution {
    public int Sum_Solution(int n) {
        int sum = n;
        boolean isEnd = (sum != 0)&&((sum += Sum_Solution(n-1))>0);
        return sum;
    }
}

48.不用加减乘除做加法

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

解析:按位运算

  • step1:按位与是查看两个数哪些二进制位都为1,这些都是进位位,结果需左移一位,表示进位后的结果
  • step2:异或是查看两个数哪些二进制位只有一个为1,这些是非进位位,可以直接加、减,结果表示非进位位进行加操作后的结果
  • step3:n1&n2是查看有没有进位位了,如果有,需要重复step1、step2;如果没有,保留n1、n2上二进制为1的部分,用或将之合为一个数,即为最后结果
public class Solution {
    public int Add(int num1,int num2) {
        int n1,n2;
        n1 = num1 & num2;
        n1 = n1<<1;
        n2 = num1 ^ num2;
        if((n1 & n2) != 0) return Add(n1,n2);
        return n1 | n2;
    }
}

49.把字符串转换成整数

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

public class Solution {
    public int StrToInt(String str) {
        if(str.length() < 1) return 0;
        char[] nums = str.toCharArray();
        int result = 0;
        int flag = 1;
        for(int i = 0 ; i<nums.length ; i++){
            if(nums[i]-'0'>9 || nums[i]-'0'<0){
                if( i==0 && (nums[i] == '+' || nums[i] == '-'))
                    flag = nums[i] == '+' ? 1 : -1;
                else
                    return 0;
            }else{
                result*=10;
                result+=(nums[i]-'0');
            }
        }
        return result*flag;
    }
}

不适用str.toCharArray()方法

public class Solution {
    public int StrToInt(String str) {
        if(str.length() < 1) return 0;
        int result = 0;
        int flag = 1;
        for(int i = 0 ; i<str.length(); i++){
            if(str.charAt(i)-'0'>9 || str.charAt(i)-'0'<0){
                if( i==0 && (str.charAt(i) == '+' || str.charAt(i) == '-'))
                    flag = str.charAt(i) == '+' ? 1 : -1;
                else
                    return 0;
            }else{
                result*=10;
                result+=(str.charAt(i)-'0');
            }
        }
        return result*flag;
    }
}

50.数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length<0) return false;
        boolean[] result = new boolean[length];
        for(int i = 0;i<length;i++){
            if(numbers[i]>length-1||numbers[i]<0) return false;
            if(result[numbers[i]]){
                duplication[0] = numbers[i];
                return true;
            }
            result[numbers[i]] = true;
        }
        return false;
    }
}

51.构建乘积数组

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1]。不能使用除法。

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        int[] B = new int[A.length];
        if(A.length == 0) return B;
        B[0] = 1;
        for(int i = 1;i<A.length;i++){
            B[i] = B[i-1] * A[i-1];
        }
        int temp = 1;
        for(int i = A.length-1;i>=0;i--){
            B[i] *= temp;
            temp *= A[i];
        }
        return B;
    }
}

==52.正则表达式匹配==

请实现一个函数用来匹配包括‘.‘和‘‘的正则表达式。模式中的字符‘.‘表示任意一个字符,而‘‘表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

解题思路

1.当patternIndex后一位为‘’时:
此时若strIndex == str.length时,直接将patternIndex+2,跳过两个;
如果strIndex!=str.length时,分为以下三种情况:
1.strIndex,patternIndex+2;(str != pattern时)
2.strIndex+1,patternIndex+2;(str = pattern 时 或者 此时pattern == ‘.’)
3.strIndex+1,patternIndex;(str == pattern 而且 str+1 也 == pattern)
2.当patternIndex后一位不为‘

此时如果strIndex = str.length return false;
如果 str = pattern 则 str+1,pattern+1
反之 return false;

public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        //1.边缘检测
        if(str==null||pattern==null) return false;
        int strIndex=0,patternIndex=0;
        return matchCore(str,pattern,strIndex,patternIndex);
    }
    public boolean matchCore(char[] str,char[] pattern,int strIndex,int patternIndex){
        if(strIndex == str.length && patternIndex == pattern.length) return true;
        if(strIndex != str.length && patternIndex == pattern.length) return false;
        //当模式中第二个字符是‘*’
        if(patternIndex+1 < pattern.length && pattern[patternIndex +1] == '*'){
            //一定注意这里strIndex有可能是str.length 需要把str[strIndex]放在后面,以免溢出
            if(strIndex != str.length && (pattern[patternIndex] == '.' || str[strIndex] == pattern[patternIndex])){
                return matchCore(str,pattern,strIndex+1,patternIndex) || matchCore(str,pattern,strIndex+1,patternIndex+2) || matchCore(str,pattern,strIndex,patternIndex+2);
            }else{
                return matchCore(str,pattern,strIndex,patternIndex+2);
            }
        }else{//模式中第二个字符不是’*‘
            if(strIndex != str.length && (str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.'))
                return matchCore(str,pattern,strIndex+1,patternIndex+1);
            else
                return false;
        }
    }
}

==53.表示数值的字符串==

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

题目分析:数值可以表示为"A+‘.‘+B+‘E/e‘+C"

  • 其中A为带符号整数,可以为空
  • B为不带符号整数,可以为空
  • A和B不能同时为空
  • C为带符号整数,不能为空
public class Solution {
    //声明一个全局变量,记录小数点前是否有数字
    boolean hasInt = false;
    public boolean isNumeric(char[] str) {
        if(str == null || str.length == 0) return false;
        return scanA(str,0);
    }
    //第一部分:为带符号整数,后续字符串可包括'./e/E'
    public boolean scanA(char[] str,int index){
        //1.如果有符号则跳过。
        if(str[index] == '-' || str[index] == '+') index++;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            hasInt = true;
            index++;
        }
        if(index == str.length) return hasInt;
        if(str[index] == '.')
            return scanB(str,index+1);
        else if(str[index] == 'e'||str[index]=='E')
            return scanC(str,index+1);
        else
            return false;
    }
    //第二部分:为不带符号整数,后续字符可带'e/E'
    public boolean scanB(char[] str,int index){
        boolean hasNum = false;
        //用于判断是否是“12.”这种数字
        if(index == str.length) return hasInt || hasNum;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            index++;
            hasNum = true;
        }
        if(index == str.length) return hasInt || hasNum;
        if(str[index] == 'e' || str[index] == 'E')
            return (hasInt || hasNum) && scanC(str,index+1);
        else
            return false;
    }
    //第三部分:为带符号整数
    public boolean scanC(char[] str,int index){
        //用于判断是否为“12e”这样的数字,这种是不正确的,第三部分不能为空
        if(index == str.length) return false;
        boolean hasNum = false;
        //如果有符号,则跳过
        if(str[index]=='+'||str[index]=='-') index++;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            hasNum=true;
            index++;
        }
        if(index == str.length) return hasNum;
        else return false;
    }
}

54.字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

输出描述:

如果当前字符流没有存在出现一次的字符,返回#字符。

import java.util.ArrayList;
import java.util.HashSet;
public class Solution {
    ArrayList<Character> list = new ArrayList<>();
    HashSet<Character> set = new HashSet<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if(!set.contains(ch))
            if(list.contains(ch)){
                //注意这里之所以将char转换为Character对象,是因为,如果直接带入char
                //函数会将char转变成ASCII码int值作为索引,会导致溢出。
                list.remove((Character)ch);
                set.add(ch);
            }else{
                list.add(ch);
            }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        if(list.size() > 0)
            return list.get(0);
        else
            return '#';
    }
}

55.链表中的入口结点

一个链表中包含环,请找出该链表的环的入口结点。
方法一:使用辅助Set集合

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
import java.util.HashSet;
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null) return null;
        HashSet<ListNode> set = new HashSet<>();
        while(!set.contains(pHead)){
            if(pHead.next == null) return null;
            set.add(pHead);
            pHead = pHead.next;
        }
        return pHead;

    }
}

方法二:单纯指针操作

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null) return null;
        ListNode p1=pHead,p2=pHead.next;
        //第一步:如果有环,则算出环的长度;
        while(p1 != p2 && p2 != null){
            p1 = p1.next;
            p2 = p2.next;
            if(p2 == null) return null;
            p2 = p2.next;
        }
        if(p2 == null) return null;
        int count = 1;
        while(p1.next != p2){
            p1 = p1.next;
            count++;
        }
        //第二步:找到环的入口
        p1 = pHead;
        p2 = pHead;
        while(count-- > 0)
            p2 = p2.next;
        while(p1!=p2){
            p1 = p1.next;
            p2 = p2.next;
        }
        return p1;
    }
}

56.删除链表中重复的结点这道题纠结了很久!!!很简单的递归就能实现,有点类似于动态规划

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null || pHead.next == null)
            return pHead;
        if(pHead.val == pHead.next.val){
          while(pHead.next != null && pHead.val == pHead.next.val)
              pHead = pHead.next;
          return deleteDuplication(pHead.next);
        }
        pHead.next = deleteDuplication(pHead.next);
        return pHead;
    }
}

57.二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode == null) return null;
        if(pNode.right != null){
            TreeLinkNode node = pNode.right;
            while(node.left != null)
                node = node.left;
            return node;
        }
        while(pNode.next != null){
            if(pNode.next.right != pNode)
                return pNode.next;
            pNode = pNode.next;
        }
        return null;
    }
}

原文地址:https://www.cnblogs.com/guoyaohua/p/8577085.html

时间: 2024-10-13 03:07:27

剑指offer 第十一天的相关文章

【剑指offer】十一。树的子结构

题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 分析:两棵树A 和B,判断B是不是A的子树,分为三种情况,一,A的根和B的根相同,则继续比较A的左子树与B的左子树,A的右子树与B的右子树.二,若A的根和B的根不同,这比较B是不是在A的左子树中,三,比较B是不是在A的右子树中.代码如下: 1 /** 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null

剑指offer(五十一)之把二叉树打印成多行

题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 代码: <span style="color:#000099;">import java.util.ArrayList; import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val

剑指offer(六十一)之字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 结果请按字母顺序输出. 输入描述: 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母. 代码: <span style="font-family:SimSun;font-size:18px;color:#000099;">import java.util.ArrayList; im

剑指offer(四十一)之翻转单词顺序列

题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,"student. a am I".后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是"I am a student.".Cat对一一的翻转这些单词顺序可不在行,你能帮助他么? 代码: <span style="font-family:SimSun;fon

剑指offer(三十一)之孩子们的游戏(圆圈中最后剩下的数)

题目描述 每年六一儿童节,NowCoder都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为NowCoder的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随机指定一个数m,让编号为0的小朋友开始报数.每次喊到m的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到NowCoder名贵的"名侦探柯

剑指offer第十一题:二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 重点掌握原码和补码的转换!!! 解题思路:对于正数使用模2取余法实现:对于负数先让它和2147483647(即:int类型下最大正数)与运算再按照正数的计算方法,最后加上一位符号位即可 代码如下: 1 public class Solution { 2 public int NumberOf1(int n) { 3 if(n==0){ 4 return 0; 5 }else if(n>0){ 6 int count = 0; 7

剑指Offer第二十一题 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列.(注意:这两个序列的长度是相等的) 思路:压栈操作次数固定,用变量记录压栈次数,同时当栈顶元素与弹出序列指针所指位置相同时,执行出栈操作. 代码实现如下: 1 import java.util.*; 2 3 public class

【剑指offer】数值的整数次方

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25506085 剑指offer上的第十一题,九度OJ上测试通过. 题目描述: 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 输入: 输入可能包含多个测试样例.对于每个输入文件,第一行输入一个整数T,表示测试案例的数目,接下来的T行每行输入一个浮点数base和一个整数exponent,两个数中间用一个空格隔开. 输出: 对应每

【剑指offer】Q38:数字在数组中出现的次数

与折半查找是同一个模式,不同的是,在这里不在查找某个确定的值,而是查找确定值所在的上下边界. def getBounder(data, k, start, end, low_bound = False): if end < start : return -1 while start <= end: mid = ( start + end ) >> 1 if data[ mid ] > k: end = mid - 1 elif data[ mid ] < k: star