二分搜索区间问题
- 建议的 范围内都是闭区间
- 用else if 不用 else
基本二分搜索
因为我们初始化 right = nums.length - 1
所以决定了我们的「搜索区间」是 [left, right]
所以决定了 while (left <= right)
同时也决定了 left = mid+1 和 right = mid-1
因为我们只需找到一个 target 的索引即可
所以当 nums[mid] == target 时可以立即返回
int binary_search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if(nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
左边界二分
因为我们初始化 right = nums.length - 1
所以决定了我们的「搜索区间」是 [left, right]
所以决定了 while (left <= right)
同时也决定了 left = mid + 1 和 right = mid - 1
因为我们需找到 target 的最左侧索引
所以当 nums[mid] == target 时不要立即返回
而要收紧右侧边界以锁定左侧边界
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定左侧边界
right = mid - 1;
}
}
// 最后要检查 left 越界的情况, left
if (left >= nums.length || nums[left] != target)
return -1;
return left;
}
右边界二分
因为我们初始化 right = nums.length - 1
所以决定了我们的「搜索区间」是 [left, righ]
所以决定了 while (left <= right)
同时也决定了 left = mid + 1 和 right = mid - 1
因为我们需找到 target 的最右侧索引
所以当 nums[mid] == target 时不要立即返回
而要收紧左侧边界以锁定右侧边界
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定右侧边界
left = mid + 1;
}
}
// 最后要检查 right 越界的情况
if (right < 0 || nums[right] != target)
return -1;
return right;
}
34. 在排序数组中查找元素的第一个和最后一个位置
int get_left (vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid - 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
if (left >= nums.size() || nums[left] != target) {
return -1;
}
return left;
}
int get_right (vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
if (right < 0 || nums[right] != target) {
return -1;
}
return right;
}
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> ans;
ans.push_back(get_left(nums, target));
ans.push_back(get_right(nums, target));
return ans;
}
240. 搜索二维矩阵 II
思路
方法1: 从左下角开始计算,先向上再向右
方法2: 逐行用二分法
bool searchMatrix(vector<vector<int>>& matrix, int target) {
for (int i = 0; i < matrix.size(); i++) {
int left = 0;
int right = matrix[0].size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (matrix[i][mid] > target) {
right = mid - 1;
} else if (matrix[i][mid] < target) {
left = mid + 1;
} else {
return true;
}
}
}
return false;
}
4. 寻找两个正序数组的中位数
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//两数组总长
int len = nums1.length + nums2.length;
//中间值的索引
int midindex = len / 2;
//定义两个变量进行迭代,总长为奇数,中位数就是mid2;总长为偶数,中位数就是mid1和mid2的平均值
int mid1 = 0,mid2 = 0;
//定义两个指针分别作为两个数组的索引
int i1 = 0, i2 = 0;
while (true) {
if (i1 + i2 == midindex + 1) break;
//依次迭代
mid1 = mid2;
//当某个指针已经到达边界,只迭代另一个指针
if (i1 == nums1.length) { mid2 = nums2[i2++]; continue; }
if (i2 == nums2.length) { mid2 = nums1[i1++]; continue; }
//两指针都为到达边界,比较大小按顺序取值
mid2 = nums1[i1] < nums2[i2] ? nums1[i1++] : nums2[i2++];
}
return len % 2 == 0? (mid1 + mid2) / 2.0 : mid2;
}
33. 搜索旋转排序数组
思路
逐渐二分缩小范围
当 [0] <= mid 的时候, 说明 [0-mid] 之间是递增序列
当[0] > mid 的时候说明[0-mid] 是先增后减序列
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (target == nums[mid]) {
return mid;
} else if (nums[0] <= nums[mid]) {
//递增序列中, target是否在中间
if (nums[0] <= target && target <= nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else if (nums[0] > nums[mid]) { // 说明[0, mid] 之间是先增后减
if (target >= nums[mid] && target <= nums[nums.length - 1]) {
left = mid +1;
} else {
right = right - 1;
}
}
}
return -1;
}