给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 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
示例 4:
输入: nums = [1,3,5,6], target = 0
输出: 0
示例 5:
输入: nums = [1], target = 0
输出: 0
此题为最经典的二分查找
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while(left < right)
{
int mid = (left+right)/2;
if(target == nums[mid]) return mid;
else if(target > nums[mid])
{
left = mid + 1;
}
else {
right = mid;
}
}
return left;
}
整数数组 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 。要求时间复杂度为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
题目要求我们的时间复杂度为log(n),所以我们很快能想到和二分查找有关。数组nums一开始为有序的,但是经过旋转之后不再整体有序,变成了两个有序的部分。
这种情况下我们每次二分先检查有序的那一半(至少有一半是有序的),如果要找的值正好在有序的这部分(比较左右边界即可判断出目标值是否在有序部分),则收缩边界,再进行二分查找。如果不在有序的部分,则再考虑无序的部分,无序的部分可以再分为两个部分,其中又有一半一定是有序的,剩下的步骤与前面一样
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size()-1;
while(left <= right)
{
int mid = (left+right)/2;
if(nums[mid] == target) return mid;
//说明mid左边有序
if(nums[mid] >= nums[left])
{
//判断目标值是否在有序部分
if(nums[mid] > target && nums[left] <= target)
{
right = mid - 1;
}
else left = mid + 1;
}
//说明mid右边有序
else
{
//判断目标值是否在有序部分
if(nums[mid] < target && nums[right] >= target)
{
left = mid + 1;
}
else right = mid - 1;
}
}
return -1;
}
给定两个大小分别为 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
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
两个数组长度是固定的,所以中位数的位置也是固定的。当两数组长度之和为奇数时,中位数下标为:(totalLength + 1) / 2
,若为偶数,中位数为 (nums[totalLength / 2] + nums[(totalLength + 1) / 2])/2
要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1]
和 pivot2 = nums2[k/2-1]
进行比较
pivot = min(pivot1, pivot2)
,两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个,这样 pivot 本身最大也只能是第 k-1 小的元素pivot = pivot1,那么 nums1[0 .. k/2-1]
都不可能是第 k 小的元素。把这些元素全部 “删除”,剩下的作为新的 nums1 数组pivot = pivot2,那么 nums2[0 .. k/2-1]
都不可能是第 k 小的元素。把这些元素全部 “删除”,剩下的作为新的 nums2 数组int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
int m = nums1.size(), n = nums2.size();
int index1 = 0, index2 = 0;
while(true)
{
if(index1 == m)
{
return nums2[index2 + k - 1];
}
else if(index2 == n)
{
return nums1[index1 + k - 1];
}
else if(k == 1)
{
return min(nums1[index1], nums2[index2]);
}
int newIndex1 = min(index1 + k / 2 - 1, m - 1);
int newIndex2 = min(index2 + k / 2 - 1, n - 1);
int pivot1 = nums1[newIndex1];
int pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2) {
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
}
else {
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
}
}
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int totalLength = nums1.size() + nums2.size();
if (totalLength % 2 == 1) {
return getKthElement(nums1, nums2, (totalLength + 1) / 2);
}
else {
return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
}
}