力扣刷题笔记:二分查找(11)

二分查找模板

寻找一个数

int binarySearch(int[] nums, int target) {
    int left = 0; 
    int right = nums.length - 1; // 注意
    while(left <= right) {
        int mid = (right + left) / 2;
        if(nums[mid] == target)
            return mid; 
        else if (nums[mid] < target)
            left = mid + 1; // 注意
        else if (nums[mid] > target)
            right = mid - 1; // 注意
        }
    return -1;
}

寻找左侧边界

int left_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0;
    int right = nums.length; // 注意
    
    while (left < right) { // 注意
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid; // 注意
        }
    }
    return left;
}

寻找右侧边界

int right_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0, right = nums.length;
    while (left < right) {
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            left = mid + 1; // 注意
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    return left - 1; // 注意
}

4. 寻找两个正序数组的中位数(二分查找)

class Solution {
public:
    int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
        /* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
         * 这里的 "/" 表示整除
         * nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
         * nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
         * 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
         * 这样 pivot 本身最大也只能是第 k-1 小的元素
         * 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
         * 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
         * 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
         */
        int m = nums1.size();
        int n = nums2.size();
        int index1 = 0, index2 = 0;
        while (true) {
            // 边界情况
            if (index1 == m) 
                return nums2[index2 + k - 1];
            if (index2 == n) 
                return nums1[index1 + k - 1];
            if (k == 1) 
                return min(nums1[index1], nums2[index2]);
            // 正常情况
            int newIndex1 = min(index1 + k / 2 - 1, m - 1);
            int newIndex2 = min(index2 + k / 2 - 1, n - 1);
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];
            if (pivot1 <= pivot2) {
                k -= newIndex1 - index1 + 1;
                index1 = newIndex1 + 1;
            }
            else {
                k -= newIndex2 - index2 + 1;
                index2 = newIndex2 + 1;
            }
        }
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int totalLength = nums1.size() + nums2.size();
        if (totalLength % 2 == 1) {
            return getKthElement(nums1, nums2, (totalLength + 1) / 2);
        }
        else {
            return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
        }
    }
};

33. 搜索旋转排序数组(二分查找)

先判断中间点,再判断左右是否为有序数组

    int search(vector<int>& nums, int target) {
        int n = (int)nums.size();
        if (!n) 
            return -1;
        if (n == 1) 
            return nums[0] == target ? 0 : -1;
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (nums[mid] == target) return mid;
            if (nums[0] <= nums[mid]) {
                if (nums[0] <= target && target < nums[mid]) 
                    r = mid - 1;
                else {
                    l = mid + 1;
            } else {
                if (nums[mid] < target && target <= nums[n - 1]) 
                    l = mid + 1;
                else
                    r = mid - 1;
            }
        }
        return -1;
    }

34. 在排序数组中查找元素的第一个和最后一个位置(两次二分查找)

用两个开放型二分查找

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans;
        //过滤特殊情况
        if(nums.size()==0)
            return {-1,-1};
		//注意必须从nums.size()开始
        int l=0,r=nums.size();

        while(l<r)
        {
            int m=l+(r-l)/2;
            if(nums[m]==target)
                r=m;
            else if(nums[m]>target)
                r=m;
            else if(nums[m]<target)
                l=m+1;
        }
        //查找结果有可能在【0,n】,过滤特殊情况
        if(l==nums.size())
            return {-1,-1};
        if(nums[l]==target)
            ans.push_back(l);
        else
            return {-1,-1};

        l=0;r=nums.size();
        while(l<r)
        {
            int m=l+(r-l)/2;
            if(nums[m]==target)
                l=m+1;
            else if(nums[m]>target)
                r=m;
            else if(nums[m]<target)
                l=m+1;
        }
        //第一次查找已经过滤了
        ans.push_back(l-1);
        return ans;
    }
};

35. 搜索插入位置(二分查找)

由于不存在要返回插入位置,所以找到第一个大于目标数的下标

    int searchInsert(vector<int>& nums, int target) {
        int l=0,r=nums.size();

        while(l<r)
        {
            int m=l+(r-l)/2;
            if(nums[m]==target)
                return m;
            else if(nums[m]>target)
                r=m;
            else if(nums[m]<target)
                l=m+1;
        }
        return l;
    }

69. x 的平方根(二分查找)

用二分查找对0-x之间的数进行查找,整数查找不用考虑小数点,查找该数的平方是否等于x

class Solution {
public:
    int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long long)mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            } else 
                r = mid - 1;
        }
        return ans;
    }
};

double类型x 的平方根(二分查找)

int compare(double a,double b)
{
	double diff=fabs(a-b);
	if(diff<1.0/100000000.0)
		return 0;
	else
	{
		return a>b?1:-1;
	}
}
 
double square_root(const double root)
{
	if(compare(root,0)<0)
		throw new exception("error");
	double left,right;
	if(compare(root,1)<0)//x>=0 && x<1
	{
		left=root;
		right=1;
	}
	else //x>=1
	{
		left=1;
		right=root;
	}
	while(compare(left,right)!=0)
	{
		double mid=left+(right-left)*0.5;
		double mul=mid*mid;
		int res=compare(mul,root);
		if(res>0)
			right=mid;
		else if(res<0)
			left=mid;
		else
			return mid;
	}
	return left;
}

153. 寻找旋转排序数组中的最小值(二分查找)

二分查找无重复情况

    int findMin(vector<int>& nums) {
        int low = 0,high = nums.size() - 1;
        while (low < high) {
            int pivot = low + (high - low) / 2;
            if (nums[pivot] < nums[high]) 
                high = pivot;
            else 
                low = pivot + 1;
        }
        return nums[low];
    }

154. 寻找旋转排序数组中的最小值 II(二分查找)

二分查找有重复情况

    int minArray(vector<int>& numbers) {
        int left=0,right=numbers.size()-1;
        while (left<right) {
            int mid = left + ( right - left) / 2;
            if (numbers[mid] < numbers[right]) 
            	right = mid;
            else if (numbers[mid]>numbers[right]) 
            	left = mid + 1;
            else right--;
        }
        return numbers[left];
    }

162. 寻找峰值(二分查找)

1、本题要求时间复杂度为logn,所以使用二分查找而不是一次遍历
2、本题只要找到一个中值即可,判断当前值和下一个值的大小,判断中值的相对位置

    int findPeakElement(vector<int>& nums) {
        int l = 0, r = nums.size() - 1;
        while (l < r) {
            int mid = l + (r - l) / 2;
            if (nums[mid] < nums[mid + 1])
                l = mid + 1;
            else r = mid;
        }
        return l;
    }

378. 有序矩阵中第 K 小的元素(二分查找)

1、本题用直接排序时间和空间复杂度爆表,用归并排序没有利用到矩阵有序的性质,用二分查找空间复杂度o(1)
2、对左上角的数=l,和右下角的数r进行二分查找,计算出比当前mid小的个数,和求的k进行比较,计算方法从左下角开始,如果数比mid小,则加上这列个数,然后向右移动,如果数比mid大,向上移动

class Solution {
public:
    bool check(vector<vector<int>>& matrix, int mid, int k, int n) {
        int i = n - 1,j = 0,num = 0;
        //每次查找从左下角开始
        while (i >= 0 && j < n) {
            if (matrix[i][j] <= mid) {
                num += i + 1;
                j++;
            } else 
                i--;
        }
        return num >= k;
    }
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int n = matrix.size(),left = matrix[0][0],right = matrix[n - 1][n - 1];
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (check(matrix, mid, k, n)) 
                right = mid;
            else 
                left = mid + 1;
        }
        return left;
    }
};

704. 二分查找(二分查找)

  int search(vector<int>& nums, int target) {
    int pivot, left = 0, right = nums.size() - 1;
    while (left <= right) {
      pivot = left + (right - left) / 2;
      if (nums[pivot] == target) return pivot;
      if (target < nums[pivot]) right = pivot - 1;
      else left = pivot + 1;
    }
    return -1;
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值