理解二分查找问题中的范围问题

Posted

技术标签:

【中文标题】理解二分查找问题中的范围问题【英文标题】:Understanding the range issue in binary seach problem 【发布时间】:2020-12-02 09:11:45 【问题描述】:

编辑: 添加有关代码背后逻辑的更多详细信息。 感谢@Stef。

我正在尝试在 LeetCode (https://leetcode.com/problems/find-the-duplicate-number/) 中解决算法问题。

下面是我解决这个问题的方法,它使用了二分搜索思想。 代码的基本逻辑是,我试图使用二进制搜索在 [1, n] 范围内找到重复的数字。

例如,如果我要在列表 [1, 3, 4, 2, 2] 中查找重复的 num。 首先统计[1, 4]的中点,因为起点是1,终点是4,所以中点是2。然后我用cntRange函数统计列表中有多少个数字在[ 1, 2]。如果数字的数量(我们有 1、2、2、3 个数字)超过了应有的数量(应该是 2),我们通过将端点设置为中点来缩小范围并继续二进制搜索,直到我们完成搜索然后我们返回起点的当前值,也就是复制的那个。

class Solution 
public:
    int findRepeatNumber(vector<int> &nums) 
        // special case we return -1
        if (nums.size() < 2) 
            return -1;
        

        // binary search to cnt the numbers in certain range
        int start = 1;
        int end = nums.size() - 1;
        while (end >= start) 

            int mid = ((end - start) >> 1) + start;
            int cnt = cntRange(nums, start, mid);

            if (end == start) 
                if (cnt > 1) 
                    return start;
                 else 
                    break;
                
            

            if (cnt > (mid - start + 1))
                end = mid;
            else
                start = mid + 1;
        
        return -1;
    

    int cntRange(vector<int> &nums, int start, int end) 
        int cnt = 0;
        for (int i = 0; i < nums.size(); ++i) 
            if (nums[i] >= start && nums[i] <= end)
                cnt++;
        
        return cnt;
    
;

这个方法传入了LeetCode,但是我很好奇[1, n]这个范围,如果范围是[0, n-1]呢?

我尝试了两个测试集: 一个是 [0, 1, 2, 0, 4, 5, 6] 另一个是 [2, 3, 1, 0, 2, 5, 3] 他们都失败了,所以我回到我的代码尝试解决这个问题。

我将 start int 初始化为 0 并更改 cnt 比较条件 从 cnt > (mid - start + 1) 到 cnt > (mid - start)。 但是在这种情况下,只通过了第一个测试,我仍然无法通过第二个。

我仍然认为这个问题是在cnt比较过程中出现的,但不知道如何解决。 有人可以帮我解决这个问题吗?

【问题讨论】:

嗨!欢迎来到***。如果您解释了代码背后的算法和逻辑,您可能会吸引更多答案。现在,我们不知道你想做什么;我们只知道您编写的一些代码没有按照您的意愿执行。 start 应该从零开始,我想。此外,在cntRange 中,您似乎使用start 作为值(与nums[i] 相比),它实际上是nums 的索引。 @500-InternalServerError,开始和结束只是数字的范围,不是索引。我之所以把start设置为1,是因为原来的问题中,数字在[1,n]的范围内,所以start应该是1。你可以看到我尝试将start改为0来解决范围为 [0, n-1] 的问题。 【参考方案1】:

您提到的 2 个案例的问题是:

start = mid + 1;

mid 的值永远不会变为负数,因此在第一次到达这条线之后 start 的最小值永远不会小于 1。这意味着在进行二分搜索时,您永远不会看到索引 0 处的值。

【讨论】:

以上是关于理解二分查找问题中的范围问题的主要内容,如果未能解决你的问题,请参考以下文章

算法 - 二分法查找

入门算法-二分查找,二分排序,插入排序,冒泡排序

Task 04:数组二分查找

二分查找解决旋转数组

搜索插入位置----二分查找

对二分算法的理解及结对编程情况