劍指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;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章