leetcode高頻題筆記之二分查找

69.x的平方根

在這裏插入圖片描述
去除x0和x1的情況,然後從1到x進行二分查找

public class Solution {

    public int mySqrt(int x) {
        if (x == 0 || x == 1) return x;
        int left = 1;
        int right = x;
        while (left <= right) {
            int mid = left + (right - left) / 2;//防止越界,用減法或者位運算
//            int mid = (right + left) >> 1;
            System.out.println(mid);
            if (mid > x / mid) right = mid - 1;//除法防止越界
            else left = mid + 1;
        }
        return right;
    }
}

牛頓迭代法:
參考題解

class Solution {
    public int mySqrt(int x) {
        long r = x;
        while (r * r > x) {
            r = (r + x / r) / 2;
        }
        return (int)r;
    }
}

367.有效的完全平方數

在這裏插入圖片描述
二分查找

class Solution {
    public boolean isPerfectSquare(int num) {
        if (num == 1) return true;
        long left = 2;
        long right = num / 2;
        while (left <= right) {
            long mid = (left + right) >> 1;
            if (mid * mid == num) return true;
            else if (mid > num / mid) right = mid - 1;
            else left = mid + 1;
        }
        return false;
    }
}

牛頓迭代法
迭代求算數平方根,如果算數平方根的平方還是num,說明是完全平方數

 class Solution {
     public boolean isPerfectSquare(int num) {
        if (num == 1) return true;
        long x = num;
        while (x * x > num) {
            x = (x + num / x) / 2;
            if (x * x == num) {
                return true;
            }
        }
        return false;
    }
}

33.搜索旋轉排序數組

在這裏插入圖片描述
二分查找:每次查找必有一邊是有序的!找到有序的一邊,判斷target在不在裏面

class Solution {
    public int search(int[] nums, int target) {

        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) >> 1;
            if (target == nums[mid]) return mid;//找到結果
            //前半段有序(可能的情況:456123,444123,因爲旋轉前是有序的,所以這個條件一定滿足)
            if (nums[left] <= nums[mid]) {
                //taget在前半段,mid位置已經判斷了,left位置還需要判斷
                if (target < nums[mid] && target >= nums[left]) {
                    right = mid - 1;
                } else {//不在前半段
                    left = mid + 1;
                }
            } else {//後半段有序(可能情況:561234)
                //target在後半段,mid位置已經判斷了,right位置還需要判斷
                if (target > nums[mid] && target <= nums[right]) {
                    left = mid + 1;
                } else {//不在後半段
                    right = mid - 1;
                }

            }
        }
        //沒找到
        return -1;
    }
}

74.搜索二維矩陣

在這裏插入圖片描述
二分查找:
將二維數組當成一維進行查找

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;

        int m = matrix.length;
        int n = matrix[0].length;
        int left = 0;
        int right = m * n - 1;
        while (left <= right) {
            int mid = (left + right) >>> 1;
            if (target == matrix[mid / n][mid % n]) return true;
            if (target > matrix[mid / n][mid % n]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return false;
    }
}

右上角爲起點的查找,查找狀態樹是一棵二叉搜索樹

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;

        int m = matrix.length;
        int n = matrix[0].length;
        int i = 0;
        int j = n - 1;
        while (i < m && j >= 0) {
            if (matrix[i][j] == target) return true;
            else if ( target>matrix[i][j]) i++;
            else j--;
        }
        return false;
    }
}

153.尋找旋轉排序數組中的最小值

在這裏插入圖片描述
如果nums[left] <= nums[right]說明這一段有序,且是我們選擇的包含拐點的部分
如果沒有序,二分查詢無序部分

class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            if (nums[left] <= nums[right]) {
                return nums[left];
            }
            int mid = (left + right) >> 1;
            //有序在左邊,就去右邊查找
            if (nums[mid] >= nums[left]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left];
    }
}
class Solution {
    public int findMin(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {

            int mid = (left + right) >> 1;
            //後半段無序
            if (nums[mid] > nums[right]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left];
    }
}

744.尋找比目標字母大的最小字母

在這裏插入圖片描述
題意:給定一個循環有序的字符數組 letters 和一個字符 target,要求找出 letters 中大於 target 的最小字符,如果
找不到就返回第 1 個字符。

public class Solution {
    public char nextGreatestLetter(char[] letters, char target) {
        int left = 0;
        int right = letters.length - 1;
        while (left <= right) {
            int mid = (left + right) >> 1;
            if (letters[mid] <= target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return left < letters.length ? letters[left] : letters[0];
    }
}

540.有序數組中的單一元素

在這裏插入圖片描述
針對偶數位的二分查找
計算中點,如果中點下標爲奇數,讓其減1,保證mid是每一組兩個數的開頭
比較mid下標值和mid+1下標值,如果相同說明這個數有兩個,left右移兩位,否則這個位置及之前出現了1個數的,將right設置爲mid

public class Solution {
    public int singleNonDuplicate(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (left + right) >> 1;
            if (mid % 2 == 1) {
                mid--;//保證查找區間大小保持奇數,保證mid是一組的開始
            }
            if (nums[mid] == nums[mid + 1]) {
                left = mid + 2;
            } else {
                right = mid;
            }
        }
        return nums[left];
    }
}

278.第一個錯誤的版本

在這裏插入圖片描述
二分查找,如果查找節點是錯誤版本,則第一個錯誤點在當前節點及之前;如果查找節點不是錯誤版本,則第一個錯誤點在當前節點之後

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        while (left < right) {
            int mid = (left + right) >>> 1;
            if (isBadVersion(mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
}

34.在排序數組中查找元素的第一個和最後一個位置

在這裏插入圖片描述
通過二分查找找到target,然後移動兩個指針找到左右邊界

public class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;

        while (left <= right) {
            int mid = (left + right) >>> 1;
            if (nums[mid] == target) {
                int l = mid;//左邊界
                int r = mid;//右邊界
                while (l - 1 >= 0 && nums[l] == nums[l - 1]) {
                    l--;
                }
                while (r + 1 < nums.length && nums[r] == nums[r + 1]) {
                    r++;
                }
                return new int[]{l, r};
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return new int[]{-1, -1};
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章