看到一个总结网址,还没来得及看完。
https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/
牛客剑指offer中一道题,二维数组中的查找
leetcode第35题Search Insert Position
文章的总结两个思路
思路1 while(left <= right)
思路2 while(left < right) 是排除,在left=right时终止,最后剩下一个元素,可能就是答案。「左右边界向中间走,两边夹」本文主要讨论思路2
1 2 3 4
| while (left < right) { 用本轮区间即leftright值算mid; 比较mid和target确定下轮区间即leftright值; }
|
举例如下 最普通二分-找到一个等于target的值就行
1 2 3 4 5 6 7 8 9 10 11 12 13
| while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else { right = mid; } }
可能找到最后也没找到,后面可能要加补丁。下面有详细介绍。
|
因为35题可以理解为找到大于等于 target 的第 11 个元素的位置,所以严格小于 target 的元素一定不是解。上面是把 (left,mid) 排除出去了所以剩下的区间就是 (mid+1,right) .
关于取中位数
基于此题解,有个记忆的口诀是「左动取左,右动取右」,即 if (…) left = mid + 1; 归为「左动」,对应左中位数;if (…) right = mid - 1; 归为「右动」,对应右中位数。 详见这个里面https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/
评论区里lzhlyle的回答。
1 2 3 4 5 6 7 8 9 10 11
| while(left<right) { mid=left+(right-left)/2; if(nums[mid]<target) left=mid+1; else if(nums[mid]>target) right=mid-1; else right=mid; }
|
1 2 3 4 5 6 7 8 9 10 11
| while(left<right) { mid=left+((right-left+1)>>1); if(nums[mid]<target) left=mid+1; else if(nums[mid]>target) right=mid-1; else left=mid; }
|
以下把等于改成大等或小等 只需要改补丁的if就行了
1 2 3 4 5 6 7 8 9 10 11
| // 查找第一个大于等于给定值的元素 private int firstLargeOrEquals(int[] arr, int target) { int l = 0, r = arr.length - 1; while (l < r) { int mid = l + ((r - l) >> 1); if (arr[mid] < target) l = mid + 1; else r = mid; // 收缩右边界不影响 first equals } if (arr[l] >= target && (l == 0 || arr[l - 1] < target)) return l; // >= return -1; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| // 查找最后一个小于等于给定值的元素 private int lastLessOrEquals(int[] arr, int target) { int l = 0, r = arr.length - 1; while (l < r) { int mid = l + ((r - l + 1) >> 1); if (arr[mid] > target) r = mid - 1; else l = mid; // 收缩左边界不影响 last equals } if (arr[l] <= target && (l == arr.length - 1 || arr[l + 1] > target)) return l; // <= return -1; }
|
---
对于704题最普通的二分查找来说标准答案给的是
1 2 3 4 5 6 7
| while(left <= right) { ··· left = mid + 1; ··· right = mid - 1; ··· }
|
搜索区间为空的时候应该终止。
如果硬要用while(left < right) 也可以但在结束后得加上一个补丁。
循环只剩一个数时候会终止,此时left=right。得判断一下他是不是target。
1 2 3 4 5 6 7 8 9
| while(left <= right) { ··· left = mid + 1; ··· right = mid - 1; ··· } if (nums[left]==target) return left;
|
https://leetcode-cn.com/problems/find-in-mountain-array/ 山脉这道题里判断mid处单调性为什么要mid和mid+1比;而不用mid和mid-1比?可能是因为前者需要
而后者要
我不确定这里说的对不对,但是前面提到过左中点要左动,也就是前者。后者会死循环。
最后更新时间: