力扣二分查找
1.搜索二维矩阵
https://leetcode.cn/problems/search-a-2d-matrix/description/?envType=study-plan-v2&envId=top-100-liked
给你一个满足下述两条属性的 m x n
整数矩阵:
- 每行中的整数从左到右按非严格递增顺序排列。
- 每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target
,如果 target
在矩阵中,返回 true
;否则,返回 false
。
示例 1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true
示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
1.暴力
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
vector<int> matrixa;
for(int i=0;i<matrix.size();i++){
for(int j=0;j<matrix[i].size();j++){
if(matrix[i][j]==target){
return true;
break;
}
}
}
return false;
}
};
2.俩次二分算法—对列进行二分和对行进行二分
class Solution {
public:
//二分搜索,可以先扫描第一列,找到所在的目标行,之后再在行内寻找目标数
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
int n = matrix[0].size();
if (matrix[0][0] > target || matrix[m - 1][n - 1] < target) {
return false;
}
//1.找到第一个大于target的行i,则目标所在的行为i-1
int left = 0;
int right = matrix.size();
int mid = 0;
while (left < right) {
mid = (left + right) / 2;
if (matrix[mid][0] < target) { //小于则目标行的下一个应该是在区间[mid+1,r)
left = mid + 1;
}
else if (matrix[mid][0] == target) {
return true;
}
else { //中间值大于target,则所找的值的范围应该在[l,mid]
right = mid;
}
}
vector<int> ii = matrix[left-1];
int l = 0;
int r = n - 1;
while (l <= r) {
mid = (l + r) / 2;
if (ii[mid] < target) {
l = mid + 1;
}
else if (ii[mid] == target) return true;
else {
r = mid - 1;
}
}
return false;
}
};
3. 一次二分算法
已知matrix为m*n,则matrix[i][j] = matrix[i*n+j]。则可以进行逆向转换。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size();
int n = matrix[0].size();
int left = 0;
int right = m*n-1 ;//指向最后一个元素
int mid = 0;
while(left<=right){
int mid = (left+right)/2;
if(matrix[mid/n][mid%n]>target){
right = mid -1;
}
else if (matrix[mid/n][mid%n]==target){
return true;
}
else{
left = mid +1;
}
}
return false;
}
};
2. 在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组 nums
,和一个目标值 target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为 O(log n)
的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
是一个非递减数组-109 <= target <= 109
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int ans1 = 0 ;
int ans2 = 0;
vector<int> ans;
int n = nums.size();
//1.二分查找第一个位置,第一个位置的前面都是小于的,则要找到第一个大于等于target的元素
int left = 0;
int right = n;
int mid = 0;
while(left<right){
mid = (left+right)/2;
if(nums[mid]<target){
left = mid + 1;
}
else {
right = mid;
}
}
if(left!=n&&nums[left]==target){
ans1 = left;
left = 0;
right = n;
//找第一个大于target的元素
while(left<right){
mid = (left+right)/2;
if(nums[mid]>target){
right = mid;
}
else{
left = mid+1;
}
}
ans2 = left -1;
}
else {
ans1 = -1;
ans2 = -1;
}
ans.push_back(ans1);
ans.push_back(ans2);
return ans;
}
};
3.旋转数组查找值
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0;
int r = nums.size() - 1;
int mid = 0;
while (l <= r) {
mid = (l + r) / 2;
if (nums[mid] == target) {
return mid;
}
//双方都有序
if (nums[l] <= nums[mid]&&nums[mid] <= nums[r]) {
if (nums[mid] > target) {
r = mid - 1;
}
else {
l = mid + 1;
}
}
//左边有序
else if (nums[l] <= nums[mid]) {
if (nums[l] <= target && target < nums[mid]) { //在左区间
r = mid - 1;
}
else { //在右区间
l = mid + 1;
}
}
//右边有序
else {
if (nums[mid] < target && target <= nums[r]) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
}
return -1;
}
};