麻烦理解稍微修改过的二进制搜索吗?

问题描述

大家好,我正在尝试解决有关leetcode的问题,称为“搜索插入位置”。继承人的问题: https://leetcode.com/problems/search-insert-position/

问题陈述: 给定一个已排序的数组和一个目标值,如果找到目标,则返回索引。如果不是,则返回按顺序插入索引的位置。

您可以假定数组中没有重复项。

这是一个简单的二进制搜索,我唯一不了解的部分是我必须在最后返回下界才能获得正确的答案。我不明白为什么。如果有人能解释我,我将不胜感激。

doRun(){
   clientConsumer.subscribe(topic);
   while( isRunAllowed() && !reConnect && !isStoppingOrStopped() && !isSuspendingOrSuspended()){
      clientConsumer.poll();
   }
   clientConsumer.unsubscribe(topic) 
} 

解决方法

取决于数组或其分区的大小(偶数或奇数),或者我们设计二进制搜索算法的方式,有时高低之间会有一个索引差异(基于停止条件,这可能会例如lo < hilo <= hi)。返回哪一个并不重要,我们只需要针对这一差异进行调整即可。

在这个问题中,lo将返回预期的结果:

public final class Solution {
    public static final int searchInsert(int[] nums,int target) {
        int lo = 0;
        int hi = nums.length - 1;

        while (lo <= hi) {
            int mid = lo + (hi - lo) / 2;

            if (nums[mid] == target) {
                return mid;
            }

            else if (nums[mid] > target) {
                hi = mid - 1;
            }

            else {
                lo = mid + 1;
            }
        }

        return lo;
    }
}
,

在找到中点之前,我们需要初始化起点。每次检查是否找到目标元素时,如果都没有找到目标元素,则更新起点。

,

要了解这一点,您必须注意练习的第二个要求:返回应插入元素的位置。 假设您要在下表中插入数字150。

╔═════╦═════╦═════╦═════╗
║ 100 ║ 200 ║ 300 ║ 400 ║
╠═════╬═════╬═════╬═════╣
║ 0   ║ 1   ║ 2   ║ 3   ║
╚═════╩═════╩═════╩═════╝

完成此操作的方法是创建一个更大的数组,将所有在 之前的元素复制到与它们相同的位置,然后添加数字150,然后复制所有出现的数字之后 150,其指数比以前高。

╔═════╦═════╦═════╦═════╦═════╗
║     ║     ║     ║     ║     ║
╠═════╬═════╬═════╬═════╬═════╣
║ 0   ║ 1   ║ 2   ║ 3   ║ 4   ║
╚═════╩═════╩═════╩═════╩═════╝

╔═════╦═════╦═════╦═════╦═════╗
║ 100 ║     ║     ║     ║     ║
╠═════╬═════╬═════╬═════╬═════╣
║ 0   ║ 1   ║ 2   ║ 3   ║ 4   ║
╚═════╩═════╩═════╩═════╩═════╝

╔═════╦═════╦═════╦═════╦═════╗
║ 100 ║ 150 ║     ║     ║     ║
╠═════╬═════╬═════╬═════╬═════╣
║ 0   ║ 1   ║ 2   ║ 3   ║ 4   ║
╚═════╩═════╩═════╩═════╩═════╝

╔═════╦══════╦═════╦═════╦═════╗
║ 100 ║  150 ║ 200 ║ 300 ║ 400 ║
╠═════╬══════╬═════╬═════╬═════╣
║ 0   ║ 1    ║ 2   ║ 3   ║ 4   ║
╚═════╩══════╩═════╩═════╩═════╝

现在您知道它是如何工作的,您知道插入所需的索引是第一个大于您的target的索引之一。如果所有数字都大于您的target,则表示0(并且所有现有数字都将移到第1到N位),如果所有数字都小于您的target,则为数字N-现有数组的长度(这不是现有数组中的合法索引,但是正如我所解释的,如果您确实想插入数字,则必须创建一个新数组。但这不属于此部分)锻炼)。

现在,为什么start是正确的索引?

当您要查找的元素不在数组中时,middle元素将永远不匹配。因此,您将startlast彼此越来越靠近。在最后一次迭代中,您最终使它们指向同一元素。在这种情况下,start == middle == last

现在,他们都指向的元素大于target或小于target

少于target

else if(target>nums[middle]){
    start=middle+1;
}

在此语句之后,我们有lastmiddle仍指向nums[middle]数字,该数字比target小。但是start将指向其后的一个位置。 nums[middle]之后的数字是大于target的第一个数字。如果您不明白为什么,请考虑我们如何从上一次迭代中解决这种情况。索引last始终指向大于target的数字,直到将其“移到”一个位置“太多”为止。

大于target

else
    last=middle-1;

在这种情况下,我们刚刚将last移动到了startmiddle以下的位置-我们知道它比* target . So... the current position is *greater*,the position where 最后一个{ 1}},那么当前位置( point is *lessstart仍指向)是大于middle的第一个数字。

在两种情况下,target都将指向正确的位置-大于start的第一个元素的位置。

让我们在示例数组中查看它。当我们尝试插入150时,会发生什么?

  1. target为0(100),start为3(400)。根据整数除法,lastmiddle,它是1(200)。 200> 150,因此我们进入(0+3)/2,并将else设置为last,它是0(100)。
  2. middle - 1最后start is still 0 (100),but 中间is now also 0 (100). They are equal,and,否则is now also 0 (100). 100 < 150,so we get to the开始`现在设置为1(200)。

因此,一旦,and 移至大于start的数字,我们便停止了,实际上插入点应该为1!

让我们对350做同样的事情

  1. target为0(100),start为3(400)。根据整数除法,lastmiddle,它是1(200)。 200 (0+3)/2,而else if现在是start,所以2(300)。
  2. middle +1是2(300),start是3(400)。 lastmiddle,即2(300)。 300 (2+3)/2,而else if现在是start,所以3(400)。
  3. middle + 1是3(400),start是3(400),中间是相同的。 400> 350,因此我们进入lastelse将移至2(300)。

现在last大于start,我们再次看到last实际上是大于350的第一个元素。确实,正确的插入点是350会是3。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...