35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为
O(log n)
的算法。示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4
提示:
1 <= nums.length <= 10^4
-10^4 <= nums[i] <= 10^4
nums
为 无重复元素 的 升序 排列数组-10^4 <= target <= 10^4
int searchInsert(vector<int>& nums, int target) {
if (nums[nums.size() - 1] < target)
return nums.size();
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target)
left = mid + 1;
else
right = mid;
}
return left;
}
74. 搜索二维矩阵
给你一个满足下述两条属性的
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
两次二分,先查找可能在哪层,再查找该层是否存在。
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n = matrix[0].size();
int left = 0, right = m - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
int k = matrix[mid][0];
if (k < target)
left = mid;
else if (k > target)
right = mid - 1;
else
return true;
}
int i = left;
if (i >= m || i < 0)
return false;
left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int k = matrix[i][mid];
if (k < target)
left = mid + 1;
else if (k > target)
right = mid - 1;
else
return true;
}
return false;
}
一次二分
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n = matrix[0].size();
int left = 0, right = m * n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int k = matrix[mid / n][mid % n];
if (k < target)
left = mid + 1;
else if (k > target)
right = mid - 1;
else
return true;
}
return false;
}
34. 在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组
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 <= 10^5
-10^9 <= nums[i] <= 10^9
nums
是一个非递减数组-10^9 <= target <= 10^9
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.size() == 0)
return {-1, -1};
int ans_left = -1, ans_right = -1;
// 左端点
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target)
left = mid + 1;
else
right = mid;
}
if (nums[left] != target)
return {-1, -1};
ans_left = left;
// 右端点
left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (nums[mid] <= target)
left = mid;
else
right = mid - 1;
}
ans_right = right;
return {ans_left, ans_right};
}
利用库函数。
vector<int> searchRange(vector<int>& nums, int target) {
if (nums.size() < 1)
return {-1, -1};
int left = lower_bound(nums.begin(), nums.end(), target) - nums.begin();
int right = upper_bound(nums.begin(), nums.end(), target) - nums.begin() - 1;
if (left >= nums.size() || nums[left] != target)
left = right = -1;
return {left, right};
}
33. 搜索旋转排序数组
整数数组
nums
按升序排列,数组中的值 互不相同 。在传递给函数之前,
nums
在预先未知的某个下标k
(0 <= k < nums.length
)上进行了 旋转,使数组变为[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]
(下标 从 0 开始 计数)。例如,[0,1,2,4,5,6,7]
在下标3
处经旋转后可能变为[4,5,6,7,0,1,2]
。给你 旋转后 的数组
nums
和一个整数target
,如果nums
中存在这个目标值target
,则返回它的下标,否则返回-1
。你必须设计一个时间复杂度为
O(log n)
的算法解决此问题。示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0 输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3 输出:-1
示例 3:
输入:nums = [1], target = 0 输出:-1
提示:
1 <= nums.length <= 5000
-10^4 <= nums[i] <= 10^4
nums
中的每个值都 独一无二- 题目数据保证
nums
在预先未知的某个下标上进行了旋转-10^4 <= target <= 10^4
当target
在左区间范围内时,right
减小,不断在左区间查找是否存在等于target的值;
当nums[mid]
在左区间,target
不左区间范围内时,left增加,去未被包含的左区间,或右区间继续查找。
int search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && nums[mid] > target) { // 在左区间
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if (nums[n - 1] >= target && nums[mid] < target) { // 在右区间
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
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)
的算法解决此问题。示例 1:
输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
示例 2:
输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。
示例 3:
输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums
中的所有整数 互不相同nums
原来是一个升序排序的数组,并进行了1
至n
次旋转
通过nums[mid] < nums[n - 1]
,来判断是否是翻转后的在数组最后一个元素下面的区间,进行不断二分。

int findMin(vector<int>& nums) {
int n = nums.size();
int left = 0, right = n - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < nums[n - 1])
right = mid;
else
left = mid + 1;
}
return nums[left];
}
4. 寻找两个正序数组的中位数
给定两个大小分别为
m
和n
的正序(从小到大)数组nums1
和nums2
。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为
O(log (m+n))
。示例 1:
输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4] 输出:2.50000 解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-10^6 <= nums1[i], nums2[i] <= 10^6
pos1
是nums1
的分割点,pos2
是nums2
的分割点,保证两个分割点左边元素总数等于或仅比右边元素总数多一个。left1
和right1
分别是nums1
分割点左右的值,left2
和right2
分别是nums2
分割点左右的值。- 若
left1 <= right2
,说明分割点是正确的方向,更新median1
和median2
,并将left
更新为pos1 + 1
。 - 若
left1 > right2
,说明分割点需要左移,将right
更新为pos1 - 1
。
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size(), n = nums2.size();
if (m > n) {
return findMedianSortedArrays(nums2, nums1);
}
int left = 0, right = m;
int median1 = 0, median2 = 0;
while (left <= right) {
int pos1 = (left + right) / 2; // nums1 的分割点
int pos2 = (m + n + 1) / 2 - pos1; // nums2 的分割点
int left1 = (pos1 == 0 ? INT_MIN : nums1[pos1 - 1]); // nums1 边界左边值
int right1 = (pos1 == m ? INT_MAX : nums1[pos1]); // nums1 边界右边值
int left2 = (pos2 == 0 ? INT_MIN : nums2[pos2 - 1]);
int right2 = (pos2 == n ? INT_MAX : nums2[pos2]);
if (left1 <= right2) {
median1 = max(left1, left2);
median2 = min(right1, right2);
left = pos1 + 1;
} else {
right = pos1 - 1;
}
}
return (m + n) % 2 == 0 ? (median1 + median2) / 2.0 : median1;
}