如果数组是排序的(通常按照递增的顺序排序),那么可以采用二分查找进行优化。可以取出位于数组中间的数字并和目标数字比较
如果中间数字正好等于目标数字,那么就找到了目标数字。如果中间数字大于目标数字,那么只需要查找数组的前半部分;如果中间数字小于目标数字,那么接下来只需要查找数组的后半部分
public int search (int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] > target) right = mid - 1;
else left = mid + 1;
}
return -1;
}
当left等于right时,查找范围是长度为1的子数组。长度为1的子数组仍然是一个有效的范围,但当left大于right时这两个下标就不能形成一个有效的查找返回,因此while循环的条件是left小于或等于right
二分查找时间复杂度为O(logn)
数组既可能是整体排序的,也可能是分段排序的,但一旦题目是关于排序数组并且还有查找操作,那么二分查找算法总是值得尝试的
思路:当目标值不在数组中时它的插入位置应该满足:①该位置上的数字大于t,②该位置的前一个数字小于t
当数组中包含目标值时,返回它在数组中的位置。由于数组中没有相同的数字,因此它前一个数字一定小于目标值。
将这两种情况统一起来:①该位置的数字大于或等于t,②该位置的前一个数字小于t
如果nums[mid]大于或等于t,那么接着比较它的前一个数字nums[mid-1]和t。如果同时满足nums[mid]≥t并且nums[mid-1]<t,那么mid就是符合条件的位置,返回mid即可。如果nums[mid]≥t并且nums[mid-1]≥t,那么符合条件的位置一定位于mid的前面,接下来在当前范围的前半部分查找。如果nums[mid]小于t,则意味着符合条件的位置一定位于mid的后面,接下来在当前范围的后半部分查找
思路:该数组特点:先递增再递减
山峰数组中的最大值是数组中唯一一个比它左右两边数字都大的数字。位于最大值前面的数字(除第一个数字之外)总是比它前一个数字大,但比它后一个数字小,位于最大值后面的数字(除最后一个数字之外)总是比它后一个数字大但比它前一个数字小
先取出位于数组中间的数字。如果这个数字比它前后两个数字都大,那么就找到了数组的最大值。
如果这个数字比它前一个数字大但比后一个数字小,那么这个数字位于数组递增的部分,数组的最大值一定在它的后面,接下来只需要在数组的后半部分查找就可以。
如果这个数字比它前一个数字小但比后一个数字大,那么这个数字位于数组递减的部分,数组的最大值一定在它的前面,接下来只需要在数组的前半部分查找就可以
在一个长度为n的山峰数组中,由于第一个数字和最后一个数字都不可能是最大值,因此初始查找范围为数组下标为1到n-2的部分
Java的语法要求函数的每个分支必须有返回值,所以在函数体的最后添加一行返回为-1的代码
思路:只出现一次的数字正好是第1个两个数字不相等的分组的第一个数字
将数组中的数字每两个分为一组。先找出中间的一组,确定这一组的两个数字是否相同。如果两个数字相同,那么那个只出现一次的数字一定在它的后面,因此接着查找它的后半部分。如果两个数字不相同,那么接着检查这一组是不是第一组两个数字不相同的分组。如果是第一组,那么这一组的第1个数字就是只出现一次的数字。如果不是第1组,那么第1组一定在它的前面,因此接着查找它的前半部分
思路:如何根据权重比例计算下标的概率。先把权重数组中的所有权重全部加起来得到权重之和,然后用每个权重之和就能得到每个下标被选择的概率
根据权重比例随机选择一个下标
可以创建另一个和权重数组的长度一样的数组nums,新数组的第i个数值sums[i]是权重数组中的前i个数字之和
也就是说,随机生成p之后,先顺序扫描累加权重数组sums找到第一个大于p的值,然后选择它对应的下标
注:累加权重数组sums是递增排序的,需要在数组中找到第1个大于随机数p的数字,因此这也是一个在排序数组中查找的问题,可用二分查找来解决
数组中第1个大于p的数字满足两个条件:①这个数字本身要大于p,②如果它前面有数字那么前一个数字要小于或等于p
在数值范围内二分查找
如果一开始不知道问题的解是什么,但是知道解的范围是多少,则可以尝试在这个范围内应用二分查找
应用这种思路的关键在于两点:①确定解的范围,即解的可能的最小值和最大值;②在发现中间值不是解之后如何判断接下来应该在解的范围的前半部分还是后半部分查找。只有每次将查找范围减少一半时才能应用二分查找