二分
在704. 二分查找 - 啤酒加点醋 - 博客园 (cnblogs.com)中,介绍了起始点left和right的选择与while()中的关系,依照目前做题看来,这个依然是对的。但在做题中,仍然会产生怀疑,以至于需要一遍遍的在本子上画示意图。目前,总结一下关于left和right的变化方法:
1. 数组中存在重复数字,需要找出某个数在数组中第一次出现的位置和最后一次出现的位置。这个时候单纯的当nums[mid]==target时就不能得出答案了。
解决 方法如下:
1. 第一次出现的位置:想象有一个标尺代表mid的位置,当nums[mid] == targert时,虽然不能确定mid是否为第一次出现的位置,但是我们需要让mid这个标尺往左移,怎么移动? right--
2. 最后一次出现的位置:同上,nums[mid] == target时,让left ++ ,直到将标尺逼到最后一次出现的位置上。
2. mid 计算方法与left 和right 的关系
通常来说我们都是向左逼近,原因是因为left和right的初始值设置和习惯。但是有一些题目需要我们向左逼近,比如69. x 的平方根 - 力扣(LeetCode) (leetcode-cn.com)。总结来说,有以下两个规律:
1. 若right需要有类似right = mid的操作,而left为left = mid + 1的操作,让mid = left + (right - left) / 2;
2. 若反过来,让mid = left + (right - left + 1) / 2;
这是考虑到当left到right之间的数字为偶数时,在某些情况下不能跳出循环的现象
以right = mid - 1; left = mid ; 且mid = left + (right - left) / 2为例子。
如果whil(left <= right),且left和right指向同一个位置,则mid = right;而又有left=mid,无法跳出循环。
如果while(left < right), 且left + 1 == right ,则mid = right;而又有left = mid,无法跳出循环。
3. 关于返回值问题。
1. 查到某个数返回坐标类问题。如果查到了,那就在while循环内返回,
2. 插入某个不存在的数,求插入坐标问题。
以35. 搜索插入位置 - 力扣(LeetCode) (leetcode-cn.com为例子:
因为while(left <= right),那么跳出循环一定是因为left == right。根据if.else语句,判定跳出循环前有left==right。
跳出有两方面原因,第一是left靠向right,是因为现在的left/right位置上的数小于target,那所以left = mid + 1 = left+1,就返回left咯;
第二是right 靠向left,是因为现在的left/right位置上的数大于target,所以呢,right = mid - 1 = left - 1 = right - 1,那就应该在现有位置上插入,故返回left。
如果代码是
class Solution { public int searchInsert(int[] nums, int target) { int left = 0; int right = nums.length; while(left < right){ int mid = left + (right - left) / 2; if(nums[mid] < target){ left = mid + 1; }else if (nums[mid] > target){ right = mid; }else{ return mid; } } return right; } }
跳出循环前一定满足left+1==right, 那跳出原因肯定是left = mid + 1 = left + 1的操作,而执行这种操作的原因是因为left处的值小于target,所以呀,应该将target插入left后,即left+1,也就是right处。不过呢,由于跳出循环后,left=rigth,所以返回哪个都是ok的。
如果以后有什么关于跳出后对left和right的判断问题迷惑的,可以仿照上述思想,判断跳出前left和right的状态,然后根据if,else语句判断。

浙公网安备 33010602011771号