本文记录的是刷题过程中的重要概念和笔记。如有侵权,请联系删除。
34. 在排序数组中查找元素的第一个和最后一个位置 *
力扣链接(opens new window)
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为 O ( log n ) O(\log n) O(logn) 的算法解决此问题吗?
示例 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]
思路
难点:设计并实现时间复杂度为
O
(
log
n
)
O(\log n)
O(logn) 的算法
一次二分查找再找出两端是O(n)
解决:两次
采用while (left <= right)的写法,区间定义为[left, right],即左闭右闭的区间
找右边的边界:
// 二分查找,寻找target的右边界(不包括target)
// 如果rightBorder为没有被赋值(即target在数组范围的左边,例如数组[3,3],target为2),为了处理情况一
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
while (left <= right) { // 当left==right,区间[left, right]依然有效
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]
} else { // 当nums[middle] == target的时候,更新left,这样才能得到target的右边界
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
- 当nums[middle] == target的时候,更新left,这样才能得到target的右边界
C++完整
class Solution {
public:
int getBorder(vector<int>& nums,int target,int signal){
// [ )
// signal: 0--left, 1--right
int left=0,right=nums.size(),mid=0;
int res=-1; // initalization: -1 not found
while(left<right){
mid=left+(right-left)/2;
if(nums[mid]>target) right=mid;
else if(nums[mid]<target) left=mid+1;
else if(nums[mid]==target && signal==0){
right=mid;
res=mid;
}else{
res=mid;
left=mid+1;
}
}
return res;
}
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(2,-1);
if(nums.size()==0) return res;
res[0]=getBorder(nums,target,0);
res[1]=getBorder(nums,target,1);
return res;
}
};
总结
- 一次不行,试试多次
- 找左找右,能否分而治之
922. 按奇偶排序数组II *
力扣题目链接(opens new window)
给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。
你可以返回任何满足上述条件的数组作为答案。
示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。
思路
很多思路,双指针
class Solution {
public:
vector<int> sortArrayByParityII(vector<int>& nums) {
int index=0;
for(int i=1;i<nums.size();i+=2){
if(nums[i] %2==0){
swap(nums[i],nums[index]);
index+=2;
i-=2;
}
}
return nums;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
或者
class Solution {
public:
vector<int> sortArrayByParityII(vector<int>& A) {
int oddIndex = 1;
for (int i = 0; i < A.size(); i += 2) {
if (A[i] % 2 == 1) { // 在偶数位遇到了奇数
while(A[oddIndex] % 2 != 0) oddIndex += 2; // 在奇数位找一个偶数
swap(A[i], A[oddIndex]); // 替换
}
}
return A;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
35.搜索插入位置 *
力扣题目链接(opens new window)
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
思路
已经做过
[ ) 的区间,分类讨论可知,退出来的时候 left==right ,此时的位置值恰好大于target。