作文以记之 ~ 二分法总结
0、前言
本篇博客是对力扣上的 二分查找 专项算法中的三个模板记录一下自己的感触!
注意:以下很多程序以及解释来源于力扣,有需要者可 点击此处 进行详细查阅!
1、三种模板
1.1 二分查找模板1
1.1.1 例程代码
int binarySearch(vector<int>& nums, int target)
{
if(nums.size() == 0)
return -1;
int left = 0, right = nums.size() - 1;
while(left <= right)
{
// Prevent (left + right) overflow
int mid = left + (right - left) / 2;
if(nums[mid] == target){ return mid; }
else if(nums[mid] < target) { left = mid + 1; }
else { right = mid - 1; }
}
// End Condition: left > right
return -1;
}
1.1.2 关键属性
- 模板1是二分查找的最基础和最基本的形式。
- 查找条件可以在不与元素的两侧进行比较的情况下确定(或使用它周围的特定元素)。
- 不需要后处理,因为每一步中,都在检查是否找到了元素。如果到达末尾,则知道未找到该元素。
1.1.3 总结
对于模板1,我觉得主要的差别在于 循环条件中设置的是 left<=right
,同时当在右边界时,right = mid-1
! 如此,才会有关键属性中说的 不用作后处理!
1.2 二分查找模板2
1.2.1 程序代码
int binarySearch(vector<int>& nums, int target)
{
if(nums.size() == 0)
return -1;
int left = 0, right = nums.size();
while(left < right){
// Prevent (left + right) overflow
int mid = left + (right - left) / 2;
if(nums[mid] == target){ return mid; }
else if(nums[mid] < target) { left = mid + 1; }
else { right = mid; }
}
// Post-processing:
// End Condition: left == right
if(left != nums.size() && nums[left] == target) return left;
return -1;
}
1.2.2 关键属性
- 一种实现二分查找的高级方法。
- 查找条件需要访问元素的直接右邻居。
- 使用元素的右邻居来确定是否满足条件,并决定是向左还是向右。
- 保证查找空间在每一步中至少有 2 个元素。
- 需要进行后处理。 当剩下 1 个元素时,循环 / 递归结束。 需要评估剩余元素是否符合条件。
1.2.3 总结
相较于模板1 ,模板2在代码上的显著差别在于 循环条件变成了left < right
,如此会导致在最后还剩下一个元素未进行判断,因此需要作后处理!而且在循环条件中是否取等号,主要差别就是 取等号时,收缩右边界 right = mid-1
,锁定左边界 ;不取等号时,就是固定右边界right = mid
,利用二分查找求左边界。简单说
- 若循环判断无等号, 则只有一边需要±1
- 若循环判断有等号,则两边都需要±1
同时,当遍历到左边范围时,其右边界的设置也变成了 right=mid
,而非right=mid-1
!
也可总结为,模板1 本质上是将目标数组分为了三部分,即 |左半部分| + |目标值| + |右半部分|
,而模板2是将目标数组分为了两部分,即 |左半部分 + 可能的目标值| + |右半部分|
,其中最后会剩下一个元素,也就是左半部分的可能的目标值,因此才需在最后一步判断这个值是否是目标值!
个人觉得,模板2中绝大多数时候,最后left
的位置可能就是目标位置,其前一个位置刚好不是,这块不像模板1!
1.3 二分查找模板3
1.3.1 程序代码
int binarySearch(vector<int>& nums, int target)
{
if (nums.size() == 0)
return -1;
int left = 0, right = nums.size() - 1;
while (left + 1 < right)
{
// Prevent (left + right) overflow
int mid = left + (right - left) / 2;
if (nums[mid] == target)
{
return mid;
}
else if (nums[mid] < target)
{
left = mid;
}
else
{
right = mid;
}
}
// Post-processing:
// End Condition: left + 1 == right
if(nums[left] == target) return left;
if(nums[right] == target) return right;
return -1;
}
1.3.2 关键属性
- 实现二分查找的另一种方法。
- 搜索条件需要访问元素的直接左右邻居。
- 使用元素的邻居来确定它是向右还是向左。
- 保证查找空间在每个步骤中至少有 3 个元素。
- 需要进行后处理。 当剩下 2 个元素时,循环 / 递归结束。 需要评估其余元素是否符合条件。
1.3.3 总结
模板 3 是二分查找的另一种独特形式。 它用于搜索需要访问当前索引及其在数组中的直接左右邻居索引的元素或条件。
与前两个模板代码上的区别,依然是在循环条件以及定界处,如模板3 循环条件变成了 left+1 < right
,既没有模板1的等号,又相较于他们多了 +1
。也就是说其终止条件变为了 left + 1 == right
,也就是左右界相邻之关系!
同时,还有一个区别就是第一步,left
和right
的初始化。特别是模板2,right=length
,这个模板的下标范围超出了数组下标。再回过头来看模板1,发现right=length-1
没有超出范围,因此模板1可以取等于,即可以令while(left<=right)
。
还有一些其他的解释,想看就 点击此处 进行分析!
2、总结
本篇博客的内容其实是对自己在力扣上专项训练时知识的记载与简单分析,挺有用的,不管是力扣上的理论,还是力扣上的题,都挺有用的,加油吧~
侵权删~