题目
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:
- 你可以假设 nums 中的所有元素是不重复的。
- n 将在 [1, 10000]之间。
- nums 的每个元素都将在 [-9999, 9999]之间
思路
想到二分查找的关键词:有序数组,数组中无重复元素
最朴素的二分查找题目,但二分查找有两个基本的难点:
-
最外层的while循环条件是low < high 还是 low<=high?
-
修改判断区间时是 high = mid 还是 high = mid - 1?
实际上由二分查找的区间决定,这个区间在整个查找过程中是不变的,也叫做循环不变量
-
左闭右闭区间,即 [ low,high ]
看low == high 是否可以取到,在这里是取得到的,举极端例子[1,1]的区间,1 == 1.
故循环条件可以有等号,即 left<=right
修改时,假设修改high,因为右闭,high可以取得到,故修改时不能有刚刚已经判断过的mid,即
修改为 high = mid -1 ,此时high初始值为nums.size() -1 也是这个道理
-
左开右闭区间,[low,high)
[1,1)有矛盾,low == high 不可以取到,故写 low<high
high取不到,写 high = mid ,即使mid已经判断过,下次判断时mid也不在判断区间内
此时high初始值为nums.size()
题解
-
左闭右闭写法
class Solution { public: int search(vector<int>& nums, int target) { int mid, low = 0, high = nums.size() - 1; while (low <= high) { mid = (low + high) / 2; if (nums[mid] > target) { high = mid - 1; } else if (nums[mid] < target) { low = mid + 1; } else if (nums[mid] == target) { return mid; } } return -1; } };
-
左闭右开写法
class Solution { public: int search(vector<int>& nums, int target) { int mid, low = 0, high = nums.size(); while (low < high) { mid = (low + high) / 2; if (nums[mid] < target) { low = mid + 1; } else if (nums[mid] > target) { high = mid; } else return mid; } return -1; } };