大家好,我是怒码少年小码。
本篇的主要内容是二分查找的扩展练习。
题目
1. 找到山脉数组的峰顶索引
LeetCode 852题。力扣的题目描述太复杂了,简单的说就是有一个数组,它里面的元素的值是先递增再递减,请你找到最大值的下标并返回。
这还不简单,最大值之前的所有元素都是 array[i] < array[i+1]
的,我们直接遍历找到第一个array[i] > array[i+1]
的下标i就是峰值索引。这种方法很容易想到,这里就不实现了,我们讲讲用二分查找怎么做:
使用二分查找进一步优化:对于mid=(left+right)/ 2;
- 如果
array[mid] > array[mid-1]
且array[mid] > array[mid+1]
,那mid是顶峰下标; 如果array[mid] > array[mid-1]
且array[mid] < array[mid+1]
,那么顶峰下标在mid的右边;- 如果
array[mid] < array[mid-1]
且array[mid] > array[mid+1]
,那么顶峰下标在mid的左边。
这就是一个二分的简单变形:
int peekIndex(int array[], int size) {
int left = 0;
int right = size - 1;
int ans;
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] > array[mid + 1]) {
ans = mid;
right = mid - 1;
}
else {
left = mid + 1;
}
}
return ans;
}
2. 寻找旋转排序数组中的最小值
LeetCode 153 :已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
- 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
- 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值互不相同的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
时间复杂度为 O(log n) 的算法解决此问题。
- 输入:nums = [3,4,5,1,2]
- 输出:1
- 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
我们记左右边界分别为low和high, mid = (low + high)/ 2
- 当nums[mid] > nums[hjgh]时,说明最小值在mid的右侧
- 当nums[mid] < nums[high]时,说明最小值在mid的左侧
int findMin(vector<int>& nums) {
int low = 0;
int high = nums.size() - 1;
while (low < high) {
int pivot = (low + high) / 2;
if (nums[pivot] < nums[high]) {
high = pivot;
}
else {
low = pivot + 1;
}
}
return nums[low];
}
3. 找到缺失的数字
数组array包含从0到n的所有整数,但其中缺了一个。
分析:可以先对数组排序。
当数组排序之后,在缺失的数据之前,所有的元素都满足array[i] = i
,在缺失的数据之后,所有的元素都满足array[i] != i
。所以可以用二分法实现。
int missingNum(int array[], int size) {
int left = 0;
int right = size - 1;
while (left < right) {
int mid = (left + right) / 2;
if (array[mid] == mid) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
return left;
}
4. 优化求平方根
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留整数部分,小数部分将被舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
int mySqrt(int x) {
int low = 0;
int high = x;
int ans;
while (low <= high) {
int n = low + (high - low) / 2;
if ((long)n * n <= x) {
ans = n;
low = n + 1;
}
else {
high = n - 1;
}
}
return ans;
}
n * n 的时候如果还是int类型在数字大的时候会溢出,所以要强转为long类型。
END
行百里者半九十,坚持!加油!!