(一)二分查找法
关键:边界的确定
[left,right]
[left,right)
在循环中必须始终坚持一种区间定义
while(left<right)/(left≤right)
if(nums[middle] > target) right=middle/middle-1
(一)左闭右闭区间 [left, right]
left=0;
//区间包含right,对于数组,下标从0-numsize-1
right = numsize -1;
//对于左闭右闭区间,[1,1]区间是合法的,因此必须包含在内,带等号
while(left <= right){
middle = (left+right)/2;
if(nums[middle]>target)
right = middle -1;
//因为已经判断了middle位置的值不合法,因此对于左闭右闭区间,必须把这个middle剔除
else if(nums[middle] < target)
left = middle + 1; //同理如上
else
return middle;
}
return -1;//一直没有找到
(二)左闭右开区间 [left, right)
left=0;
//因为该区间不包含right,所以right=numsize
right = numsize;
//对于左闭右开区间,[1,1)区间是不合法的,因此不能带等号
while(left < right){
middle = (left+right)/2;
if(nums[middle]>target)
//对于左闭右开区间,本身就不包含middle,因此不需要-1
right = middle;
else if(nums[middle] < target)
// 对于左闭右开区间,左边是包含的,所以要剔除middle
left = middle + 1;
else
return middle;
}
return -1;//一直没有找到
总结:根据不同的区间定义,left和right的边界取值需要注意。
(二)移除元素
数组中的元素不可以被删除,只能被覆盖
vector 中的erase函数
erase为一个O(N)的函数,删掉一个元素,后面所有元素前移
法一:暴力实现(双for循环 O(N*N))
法二:双指针(O(N))
一层for循环
快指针(fast):寻找旧数组中需要删除的元素,将需要保留的元素赋值给新数组
慢指针(slow):新数组的当前下标(在旧数组基础上更新)
slow = 0;
//移动快指针
for(fast = 0;fast < nums.size; fast++)
if(nums[fast] != val){ //需要保留的元素,更新新数组
nums[slow] = nums[fast]; (nums[slow++]=nums[fast])
slow++; //慢指针后移
}
return slow;
(三)有序数组的平方
平方后的大小
大 → 小 ← 大
(左指针)(右指针)
双指针方法,由两边向中间推进,新的数组由大向小填入
vector<int> result;
k = nums.size - 1; // 新数组由大到小填入
for(i = 0, j = nums.size - 1; i < = j;)
if(nums[i]^2 > nums[j]^2){ //取左边元素
result[k] = nums[i]^2;
k--;
i++;
}else{ //包括小于和等于
result[k] = nums[j]^2;
k--;
j--;
}
return result;
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result(nums.size(),0);
int k = nums.size() - 1;
for(int i=0,j=nums.size()-1; i <= j;){
if(nums[i]*nums[i] > nums[j]*nums[j]){
result[k] = nums[i]*nums[i];
i++;
k--;
}else{
result[k] = nums[j]*nums[j];
k--;
j--;
}
}
return result;
}
};
(四)长度最小的子数组
滑动窗口(双指针法)
用for循环中的j确定终止位置
起始位置的确定(精华):
当发现起始和终止元素中的元素和大于s的时候,移动起始位置,缩小区间
result = Max;
// 用j指向终止位置,试探上界
for(j=0; j<= nums.size-1;j++){
sum += nums[j];
//这里不能是if(sum >= s),因为这里需要不断移动前指针,试探出符合sum>s的最短组合长度
while(sum >= s){
subL = j - i + 1;
result = min(result,subL); //保留最小值
sum - = nums[i]; // 前指针后移,sum要减去前指针当前元素值
i++; //前指针后移
} //end-while
} //end-for
return result;
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int subL = 0;
int i = 0;
for(int j = 0; j < nums.size(); j++){
sum += nums[j];
while(sum >= target){
subL = j -i +1;
result = result < subL ? result: subL;
sum -= nums[i];
i++;
}
}
return result == INT32_MAX ? 0 : result;
}
};
(五)螺旋矩阵
关键点:边界处理
循环不变量:对每条边的处理规则不变 (左闭右开 [ )/ 左闭右闭 [ ])
左闭右开法:
startx = 0; //起始位置行号
starty = 0; //起始位置列号
offset = 1; //终止位置的偏移量
count = 1; //矩阵赋值,从1到N*N
//循环遍数(转几圈)
while(n/2){
//遍历上边, i不变
for(j = starty; j < n - offset; j++){
nums[startx][j] = count ++;
}
//遍历右边,此时j=n-offset,j的值固定
for(i = startx; i< n - offset; i++){
nums[i][j] = count ++;
}
//遍历下边,此时j=n-offset,j不需要再初始化
for(;j > starty; j--){
nums[i][j] = count ++;
}
//遍历左边,此时i = n-offset, i不需要再初始化
for(; i > startx; i--){
nums[i][j] = count ++;
}
//每转一圈,更新startx,starty,offset
startx ++;
starty ++;
offset ++;
}
// 如果n为奇数,最后还需要填补最中间的空缺
if(n%2 == 1) nums[i][j] = count;
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> result(n, vector<int>(n,0));
int startx = 0;
int starty = 0;
int offset = 1;
int count = 1;
int num = n/2;
int mid = n/2;
int i, j;
while(num--){
for(j = starty; j < n - offset; j++){
result[startx][j] = count++;
}
for(i = startx; i < n - offset; i++){
result[i][j] = count++;
}
for(; j > starty; j--){
result[i][j] = count++;
}
for(; i> startx; i--){
result[i][j] = count++;
}
startx++;
starty++;
offset++;
}
if(n%2 == 1) result[mid][mid] = count;
return result;
}
};