Leetcode中的二分题目

这一次的二分姿势都是学习上一篇文章的。

Leetcode 33. Search in Rotated Sorted Array
一个不是标准递增的序列
那么你就要先找到那个分界点。

第一想法是,与target比大小得到分界点。但是会出现一些问题,因为有可能target比所有序列数都大(或者都小),就会出现问题。于是只能用序列内的数作为标杆。
第二想法就是,得到了分界点之后,分两段开始二分。这样也行,但是太麻烦了。于是发现分界点也是一个类似于循环节点的东西。所以通过取模进行平移,简化代码。

最后注意的是,通过平移得到的位置,在输出答案的时候要记得平移回去。我就是没有平移回去错了好几次。

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        n = len(nums)
        l = -1
        r = n - 1

        while l + 1 < r:
            mid = l + (r - l >> 1)
            if nums[mid] > nums[r]:
                l = mid
            else:
                r = mid

        half = r

        l = 0
        r = n
        while l + 1 < r:
            mid = l + (r - l >> 1)
            realmid = (mid + half) % n
            if nums[realmid] > target:
                r = mid
            else:
                l = mid

        if nums[(l+half)%n] == target:
            return (l+half)%n
        else:
            return -1

Leetcode 34. Search for a Range

下限是lower_bound
上限是upper_bound-1
感觉这里左闭右开,左开右闭都行。
只是一个是区间下限,一个是区间上限,所以我就用各自能够取到的位置去求。

class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        l = -1
        r = len(nums) - 1
        ans = [0, 0]
        while l+1 < r:
            mid = l + (r - l >> 1)
            if nums[mid] >= target:
                r = mid
            else:
                l = mid
        if nums[r]!= target:
            ans[0] = -1
        else:
            ans[0] = r

        l = 0
        r = len(nums)
        while l+1 < r:
            mid = l + (r - l >> 1)
            if nums[mid] <= target:
                l = mid
            else:
                r = mid

        if nums[l]!= target:
            ans[1] = -1
        else:
            ans[1] = l
        return ans

Leetcode 35. Search Insert Position
找到最小的大于等于target的值的位置
要用左开右闭,judge是递增性质的(越大的数,越可能是大于target的值)。
当然,也可以认为这样更加方便地得到大于target的位置。

class Solution(object):
    def searchInsert(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        l = -1
        r = len(nums)

        while l+1 < r:
            mid = l + (r - l >> 1)
            if nums[mid] < target:
                l = mid
            else:
                r = mid

        return r

Leetcode 69. Sqrt(x)
用的是左闭右开
用左开右闭没有成功,不过应该是有一些不太好看的姿势可以过的吧。

class Solution(object):
    def mySqrt(self, x):
        """
        :type x: int
        :rtype: int
        """
        if x == 0 or x == 1:
            return x
        l,r = 0, x/2+1
        while l+1<r:
            mid = l + ((r - l) >> 1)
            if mid**2 <= x:
                l = mid
            else:
                r = mid
        return l

Leetcode 74. Search a 2D Matrix

这题最关键的问题是mid = (l+r)/2上下取整的问题。
如果是下取整,会出现死循环或者答案不对的情况,我不太明白为什么会出现这个问题。但是确实是会发生。
第一个二分,我们要求的是小于val的最大值。

假设区间为[l,r],中间值为mid。
如果num[mid] > val
则区间变成[l,mid-1]
否则变成[mid,r]
因此,如果采用下取整的方式,r-l<=1的时候,l不变,为避免这种情况,则采用上取整。

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.empty())  return false;

        int n = matrix.size(); //行数
        int m = matrix[0].size();//列数

        if(matrix[0][0] > target || matrix[n-1][m-1] < target)  return false;
        int l = 0, r = n - 1;
        while(l <= r)
        {
            int mid = l + (r - l + 1 >> 1);
            if(matrix[mid][0] > target) r = mid - 1;
            else if(matrix[mid][0] < target) l = mid + 1;
            else return true;
        }
        int row = r; 
        l = 0, r = m - 1;
        while(l <= r)
        {
            int mid = l + (r - l >> 1);
            if(matrix[row][mid] > target) r = mid - 1;
            else if(matrix[row][mid] < target) l = mid + 1;
            else return true;
        }
        return false;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值