leetcode——二分查找系列题目(C++)

题目列表

    • 69. x 的平方根
    • 744. 寻找比目标字母大的最小字母
    • 540. 有序数组中的单一元素
    • 278. 第一个错误的版本
    • 153. 寻找旋转排序数组中的最小值
    • 34. 在排序数组中查找元素的第一个和最后一个位置

69. x 的平方根

leetcode——二分查找系列题目(C++)_第1张图片

  • 二分查找即可,其中mid的平方可能会超出int的类型,所以转成long long 在比较,由于left+1,可能会去除正确结果,最后在核实一下即可
class Solution {
public:
    int mySqrt(int x) {
        int  left = 0, right = x;
        while(left < right){
            int mid = (right + left) / 2;
            if((long long)mid * mid == x)
                return mid;
            else if((long long)mid * mid > x)
                right = mid - 1;
            else 
                left = mid + 1;
        }
        if((long long)left * left > x)              
left--;
        return left;
    }
};

744. 寻找比目标字母大的最小字母

leetcode——二分查找系列题目(C++)_第2张图片
leetcode——二分查找系列题目(C++)_第3张图片

  • 给定一个有序的字符数组 letters 和一个字符 target,要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 个字符。
class Solution {
public:
    char nextGreatestLetter(vector<char>& letters, char target) {
        int left = 0, right = letters.size() - 1;
        if(letters[right] <= target)
            return letters[0];
        while(left <= right){
            int mid =left + (right - left) / 2;
            if(letters[mid] > target)
                right = mid-1;
            else
                left = mid+1;
        }
        return letters[left];
    }
};

540. 有序数组中的单一元素

leetcode——二分查找系列题目(C++)_第4张图片

  • 要求以 O(logN) 时间复杂度进行求解,因此不能遍历数组并进行异或操作来求解,这么做的时间复杂度为 O(N)。
  • 因为只有一个单的,所以我们只需要对偶数索引进行二分搜索即可。如果 nums[m] == nums[m + 1],那么 index 所在的数组位置为 [m + 2, r],此时令 l = m + 2;如果 nums[m] != nums[m + 1],那么 index 所在的数组位置为 [l, m],此时令 r = m。由于采用r = m的赋值形式,所以循环条件为l leetcode——二分查找系列题目(C++)_第5张图片
class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(mid % 2 == 1)
                mid--;
            if (nums[mid] == nums[mid + 1])
                left = mid + 2;
            else 
                right = mid;
        }
        return nums[left];
    }
};

278. 第一个错误的版本

leetcode——二分查找系列题目(C++)_第6张图片

  • 如果第 m 个版本出错,则表示第一个错误的版本在 [l, m] 之间,令 h = m;否则第一个错误的版本在 [m + 1, h] 之间,令 l = m + 1。
  • 因为 h 的赋值表达式为 h = m,因此循环条件为 l < h。
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int left = 1 ,right = n;
        while(left < right){
            int mid = left + (right -left) / 2;
            if(isBadVersion(mid) == true)
                right = mid;
            else 
                left = mid + 1 ;
        }
        return left;
    }
};

153. 寻找旋转排序数组中的最小值

leetcode——二分查找系列题目(C++)_第7张图片

  • 如果nums[mid] > nums[right],则表示index在 [mid + 1,right] 之间,令 left = mid + 1;否则在 [left, mid] 之间,令 right = mid。
  • 因为right的赋值表达式为 right = mid。因此循环条件为 left < right。
class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0 , right = nums.size() - 1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[right])
                left = mid + 1;
            else
                right = mid;
        }
        return nums[left];
    }
};

34. 在排序数组中查找元素的第一个和最后一个位置

leetcode——二分查找系列题目(C++)_第8张图片

  • 可以用二分查找找出第一个位置和最后一个位置,但是寻找的方法有所不同,需要实现两个二分查找。我们将寻找 target 最后一个位置,转换成寻找 target+1 第一个位置,再往前移动一个位置。这样我们只需要实现一个二分查找代码即可。

  • 我们的查找函数只能返回target可能在数组中的位置,并不保证该target一定存在数组中,所以判断时要加以判断。

  • 在寻找第一个位置的二分查找代码中,需要注意 h 的取值为 nums.length,而不是 nums.length - 1。先看以下示例:

nums = [2,2], target = 2

  • 如果 h 的取值为 nums.length - 1,那么 last = findFirst(nums, target + 1) - 1 = 1 - 1 = 0。这是因为 findLeft 只会返回 [0, nums.length - 1] 范围的值,对于 findFirst([2,2], 3) ,我们希望返回 3 插入 nums 中的位置,也就是数组最后一个位置再往后一个位置,即 nums.length。所以我们需要将 h 取值为 nums.length,从而使得 findFirst返回的区间更大,能够覆盖 target 大于 nums 最后一个元素的情况。
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int first = findFirst(nums,target);
        int last = findFirst(nums,target+1) - 1;
        if(first == nums.size() ||nums[first] != target ){
            return vector<int> {-1 , -1};
        }else{
            return vector<int>{first,max(first,last)};
        }
    }
    
    int findFirst(vector<int>& nums, int target){
        int l = 0 ,r = nums.size();
        while(l < r){
            int m = l + (r - l) / 2;
            if(nums[m] < target)
                l = m + 1;
            else
                r = m;
        }
        return l;
    }
};

你可能感兴趣的:(数据结构和算法)