数组
1. 二分查找法/二分搜索法
[left, right] (左闭右闭版本,也就是左可以等于右版本) :根据区间来写right 和 left的取值也就是+1或者-1,如果while里面写的是<=也就是有等号,说明后面的取值要符合定义,也就是取值合法。如[1,1] (包含1,又包含1,所以是一个合法的区间);写right = middle是不合法的,因为middle不是我们要寻找的值,而应该写right = middle -1
// [left, right]是合法区间
left = 0;
right = numSize - 1;
while(left <= right)
{
middle = (left + right)/2;
if(nums[middle] > target){
right = middle - 1;
}
else if(nums[middle] < target){
left = middle + 1;
}
else return middle;
}
return -1;
[left, right) (左闭右开版本) :举例子[1,1)既包含1,又不包含1,是一个不安全的,所以循环条件♻️是left < right。因为是右开,所以更新right的时候是right = middle
// [left, right)是合法区间
left = 0;
right = numSize;//小心
while(left < right)
{
middle = (left + right)/2;
if(nums[middle] > target){
right = middle;
}
else if(nums[middle] < target){
left = middle + 1;
}
else return middle;
}
return -1;
class Solution {
public:
int search(vector<int>& nums, int target) {
//[left,right]
int left = 0;
int right = nums.size() - 1;
while(left <= right)
{
int middle = (left + right)/2;
if(nums[middle] > target)
right = middle - 1;
else if(nums[middle] < target)
left = middle + 1;
else return middle;
}
return -1;
}
};
class Solution {
public:
int search(vector<int>& nums, int target) {
// [left, right)
int left = 0;
int right = nums.size(); //这一步要小心,定义的时候
while(left < right){
int middle = left + (right - left)/2;
if(nums[middle] < target) left = middle + 1;
else if(nums[middle] > target) right = middle;
else return middle;
}
return -1;
}
};
2. 移除元素
使用双指针
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int fast = 0 , slow = 0;
for(fast = 0; fast < nums.size(); fast++)
{
if(nums[fast]!= val){
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
3. 删除有序数组中的重复项
用到的是快慢指针,和移除元素一个思想
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int fast = 0, slow = 0;
for(fast = 0; fast< nums.size(); fast++){
if(nums[fast] != nums[slow])
{
slow++;
nums[slow] = nums[fast];
}
}
return slow + 1;
}
};
4. 有序数组的平方
从前和从后往里面缩,将初始化的vector从后往前赋值(从前往后是从小到达,那么从后往前就是从大到小)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int newSize = nums.size() - 1;//尾指针的下标
vector<int> newNums(nums.size(),0);
for(int i = 0 , j = nums.size() - 1; i <= j ;)
{
if(nums[i] * nums[i] < nums[j] * nums[j]){
newNums[newSize] = nums[j] * nums[j];
--j;
}
else{
newNums[newSize] = nums[i] * nums[i];
++i;
}
newSize--;
}
return newNums;
}
};
5. 长度最小的子数组
需要一个头指针,一个尾指针,尾指针先走,头指针不断靠近尾指针,只要满足两个指针中间包括两个指针指的元素之和大于等于target,头指针一个一个往后挪,记得sum要减去每一个头指针指向的数值,遍历完后返回target
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int j = 0, i = 0;
int ret = INT32_MAX;//结果值
int sum = 0; //用来临时保存滑动内的总和
for(j = 0; j < nums.size(); ++j)
{
sum += nums[j];
while(sum >= target){
ret = min(j - i + 1, ret);
sum -= nums[i];
++i;
}
}
if(ret == INT32_MAX)return 0;
return ret;
}
};
6. 螺旋矩阵 II
因为是顺时针旋转赋值,我们需要计算旋转轮数,轮数loop是n/2,一圈遍历四次,每次一条边少一个元素留给下一条边遍历(也就是说的左闭右边开),遍历完一圈记得设置开始遍历位置(startx, starty),以及offset要加一(因为offset是用来计算右开的位置); 最后如果是奇数,还要补最中间的格子
注:不要忘了starts,starty在循环开始地方的更新
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n,0));//vector定义二维数组
int loop = n/2;
int startx = 0 , starty = 0;
int offset = 1;
int i = 0, j = 0;
int count = 1; //count是从1开始慢慢+1的
while(loop--)
{
//第一步一定不要缺,更新startx,starty
i = startx;
j = starty;
for(j = starty; j < n - offset; ++j)res[i][j] = count++; // 因为坐标(i,j),这边j在变化, 遍历左到右
for(i = startx; i < n - offset; ++i) res[i][j] = count++;//遍历右上到右下
for(; j > starty; --j) res[i][j] = count++;//遍历右下到左下
for(; i > startx; --i) res[i][j] = count++;//遍历左下到左上
startx++;
starty++;//初始点的更新,更新到右下的格子
offset++;
}
if(n%2)res[n/2][n/2] = count;
return res;
}
};