剑指offer刷题记录(四)

1.

我的解法很简答:1ms

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length == 0) return 0;
        if(target >nums[nums.length-1] || target<nums[0]) return 0;
        int i = 0;
        int count = 0;
        while(nums[i]<=target){
            if(nums[i] == target){
                count++;
            }
            if(i == nums.length-1) break;
            i++;
        }
        return count;
    }
}

二分查找:这个要会去写,二分查找就是用于排好序后的数组查找。

class Solution {
    public int search(int[] nums, int target) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= target) i = m + 1;
            else j = m - 1;
        }
        int right = i;

        i = 0; j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] < target) i = m + 1;
            else j = m - 1;
        }
        int left = j;
        
        return right - left - 1;
    }
}

2.

我的解法:

class Solution {
    public int minArray(int[] numbers) {
        if(numbers.length == 0) return 0;
        if(numbers.length == 1) return numbers[0];
        int i =1;
        while(numbers[i] >=numbers[i-1]){
            if(i == numbers.length-1) return numbers[0];
            i++;
        }
        return numbers[i];
    }
}

大佬的解法:很简洁,还是二分法,但是得理解

class Solution {
    public int minArray(int[] numbers) {
        int i = 0, j = numbers.length - 1;
        while (i < j) {
            int m = (i + j) / 2;
            if (numbers[m] > numbers[j]) i = m + 1;
            else if (numbers[m] < numbers[j]) j = m;
            else j--;
        }
        return numbers[i];
    }
}

3.

我的解法:理解起来很简单,双百

class Solution {
    public int missingNumber(int[] nums) {
        if(nums[0] != 0) return 0;
        if(nums.length == 1){
            if(nums[0] == 0){
                return 1;
            }else{
                return 0;
            }
        }
        int res = 0;
        int count =0;
        for(int i=1;i<nums.length;i++){
            if(nums[i]-nums[i-1] != 1){
                res = i;
                count = 1;
                break;
            }
        }
        if(count == 0) return nums.length;
        return res;

    }
}

大佬的代码非常简单,就是使用二分查找,需要注意的一点,对于有序或者部分有序的数组,首先就要往二分法上去想

class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] == m) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}

4.

我没有做出来。这题目确实有些难度,看到一个大佬用单调双向队列来做,我觉得思路很好:

选择单调递减的双向队列,里面存入的是索引值。

获取的元素比队列最后一个元素都小,那就说明比整个队列的元素都小,但是因为它靠后,不能不理它,所以要将它加入;如果获取的元素比队列最后K个元素都大,那就把这K个元素弹出,再将这个获取的元素放到队列尾部。为什么要把它们弹出(删除),现在它们肯定比获取的元素早一点离开滑窗,而且还比获取的元素小,所以它们就没有价值了。最后还要注意队列第一个元素(最大值)何时会离开滑窗,注意把它弹出即可。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || k < 1 || nums.length < k) {
            return new int[0];
        }

        int index = 0;
        int[] res = new int[nums.length - k + 1];
        LinkedList<Integer> qMax = new LinkedList<>();

        for (int i = 0; i < nums.length; i++) {
            // 在队列不为空的情况下,如果队列尾部的元素要比当前的元素小,或等于当前的元素
            // 那么为了维持从大到小的原则,我必须让尾部元素弹出
            while (!qMax.isEmpty() && nums[qMax.peekLast()] <= nums[i]) {
                qMax.pollLast();
            }
            // 不走 while 的话,说明我们正常在队列尾部添加元素
            qMax.addLast(i);
            // 如果滑动窗口已经略过了队列中头部的元素,则将头部元素弹出
            if (qMax.peekFirst() == (i - k)) {
                qMax.pollFirst();
            }
            // 看看窗口有没有形成,只有形成了大小为 k 的窗口,我才能收集窗口内的最大值
            if (i >= (k - 1)) {
                res[index++] = nums[qMax.peekFirst()];
            }
        }
        return res;
    }
}

5.

这道题有一定的难度,附上一个大佬的思路,使用边界+循环来处理这个循环打印。

这里有个细节:1.矩阵的行数和列数怎么表示? 矩阵的列:Matrix[0].length  矩阵的行:Matrix.length

如果用边界来做,最最关键的是边界向内收缩条件和是否打印完毕条件,这两个条件如果清晰了,就好做了。

class Solution {
    public int[] spiralOrder(int[][] matrix) {
       if(matrix.length == 0) return new int[0];
       int l = 0;//左边界
       int r = matrix[0].length -1;//右边界
       int t = 0;//上边界
       int b = matrix.length - 1;//下边界
       int x = 0;//数组的索引
       int[] res = new int[(r+1)*(b+1)];//数组长度相当于长*宽
       while(true){
           for(int i=l;i<=r;i++){
               res[x++] = matrix[t][i];
           }
           if(++t>b) break;
           for(int i=t;i<=b;i++){
               res[x++] = matrix[i][r];
           }
           if(l>--r) break;
           for(int i=r;i>=l;i--){
               res[x++] = matrix[b][i];
           }
           if(t>--b) break;
           for(int i=b;i>=t;i--){
               res[x++] = matrix[i][l];
           }
           if(++l>r) break;
       }
        return res;
    }
}

6.

这道题确实很有趣味性,很有意思。我是用我自己的思路,先把这个数组排序,这样知道有没有0,有个0,然后再看后面的数是不是递增1的方式排列,如果不是,中间有多少间隔,就是看0(大小王)能不能补上这个缺口。

class Solution {
    public boolean isStraight(int[] nums) {
        Arrays.sort(nums);
        int loss = 0;
        int i = 0;
        int count = 0;
        while(i<=4){
            if(nums[i] == 0){
                count++;
                i++;
                continue;
            }
            if(i-count>0){
                int def = nums[i]-nums[i-1];
                if(def == 0) return false;
                if(def > 1){//有间隔
                    loss+=def-1;
                }
            }
            i++;
        }
        if(loss <= count) return true;
        return false;

    }
}

7.

是一道求多少种可能性的题目,一般这种题目都是会有递推的关系。这时候就要往动态规划上的联想。

这是一个大佬的答案,我觉得写得很好。思路如下:

class Solution {
    public int numWays(int n) {
        int a = 1, b = 1, sum;
        for(int i = 0; i < n; i++){
            sum = (a + b) % 1000000007;
            a = b;
            b = sum;
        }
        return a;
    }
}

8.

我的解法:双百

就是二分法,思路就是拿每一行的第一个元素和最后一个元素和目标元素进行比较,如果目标元素介于两者之间,这一行就要二分法去寻找,看看有没有这个数,没有就往下寻找。

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        int col = matrix.length;
        if(col == 0) return false;
        int row = matrix[0].length;
        if(row == 0) return false;
        for(int i =0;i<col;i++){
            if(matrix[i][0] <= target && matrix[i][row-1] >= target ){
                int k = 0;
                int j = row;
                while(k <= j) {
                    int m = (k + j) / 2;
                    if(matrix[i][m] == target){
                        return true;
                    }else if(matrix[i][m]<target){
                        k = m + 1;
                    }else{
                        j = m - 1;
                    } 
                }
            }
        }
        return false;
    }
}

大佬的解法:代码更简单

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        int i = matrix.length - 1, j = 0;
        while(i >= 0 && j < matrix[0].length)
        {
            if(matrix[i][j] > target) i--;
            else if(matrix[i][j] < target) j++;
            else return true;
        }
        return false;
    }
}

9.

我的解法:

1.split()方法来按照空格切分成一个string数组

2.给的string s 前后可能有空格,这里调用trim()方法来去除前后空格

3.但此题中不光前后有空格,可能在单词中的空格数不只1个,那token数组里就可能有空元素,如何来判断字符串空,

这里使用光写a==null是不行的,得写if(a == null ||"".equals(a))

class Solution {
    public String reverseWords(String s) {
        if(s == null||"".equals(s)) return null;
        String S = s.trim();
        String[] tokens = S.split(" ");
        LinkedList<String> list = new LinkedList<>();
        for(String a:tokens){
            if(a == null ||"".equals(a)) continue;
            list.addFirst(a);
        }
        StringBuilder str = new StringBuilder();
        while(!list.isEmpty()){
            str.append(list.removeFirst());
            if(list.size() != 0) str.append(" ");     
        }
        String res = str.toString();
        return res;
    }
}

大佬的双指针解法:

class Solution {
    public String reverseWords(String s) {
        if(s == null) return null;
        s = s.trim();
        int j = s.length()-1;
        int i = j;
        StringBuilder res = new StringBuilder();
        while(i>=0){
            while(i>=0 && s.charAt(i) != ' ') i--;//从尾部开始,非空格的地方
            res.append(s.substring(i+1,j+1)+" ");
            while(i>=0 && s.charAt(i) == ' ') i--;//把两个单词中间的空格去掉
            j = i;
            
        }     
        return res.toString().trim();
    }
}

10.

和前面的青蛙跳台一样,属于一道题

class Solution {
    public int fib(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        int a = 0;
        int b = 1;
        int sum = 0;  
        for(int i =0;i<n;i++){
            sum = (a+b) % 1000000007;
            a = b;
            b = sum;
        }
        return a;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值