力扣题目链接
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
数组有序,数组中无重复元素
每次找数组的中点,然后与目标值进行对比。
循环终止条件判断,while(low <= high) 此时low == high有意义,所以要加等号。
class Solution {
public:
int search(vector& nums, int target) {
//二分查找
int n = nums.size();
int left = 0, right = n - 1; //定义初始查找边界为左闭右闭
while(left <= right){ //等号要加上
int mid = left + (right - left)/2; //等同于 (left+right)/2,防止数组溢出
if(nums[mid] > target) right = mid - 1; //在左半部分查找
else if(nums[mid] < target) left = mid + 1; //在右半部分查找
else return mid; //找到,返回对应下标
}
return -1; //未找到,返回-1
}
};
//在c++的语法当中,存在内置函数进行二分的查找,在编程的时候可以采用内置函数的方法
//lower_bound(val),在数组中找到大于等于val值的第一个元素下标位置
//upper_bound(val),在数组中找到大于val值的第一个元素下标位置
//时间复杂度为O(logn)
//空间复杂度为O(1)
力扣题目链接
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
所以采用双指针的写法对原先的内存进行覆盖
一次循环,只有在right指针不等于值val的情况下,left才进行移动。
class Solution {
public:
int removeElement(vector& nums, int val) {
//双指针,当数组下表为val的时候,left不移动,只有当数组值不为val的时候,left才进行移动
int n = nums.size();
int left=0; //left作为数组的存储下标,存储不等于val值的元素
int right = 0; //right作为遍历数组的下标
for(right = 0; right < n; right++){
if(nums[right] != val){
nums[left++] = nums[right];
}
}
return left;
}
};
// 时间复杂度:O(n)
// 空间复杂度:O(1)
类似于快速排序的思想,左指针用来寻找等于val值的元素,右指针来寻找不等于val值的元素,然后找到之后,进行元素之间的交换,这个写法改变了元素之间的相对位置。
class Solution {
public:
int removeElement(vector& nums, int val) {
/*写法二
也是双指针写法,但是与第一种有些区别。左右指针,一个从头开始找元素等于val,一个从末尾开始找不是val的,然后元素之间的值进行交换
*/
int n = nums.size();
int left = 0, right = n - 1;
while(left <= right){
while(left <= right && nums[left] != val) left++;
while(left <= right && nums[right] == val) right--;
if(left <= right){
nums[left++] = nums[right--];
}
}
return left;
}
};
力扣题目链接
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
双指针解法
一个指针从头开始比较,
一个指针从尾开始比较,
大的数的话,放在最后面,然后对应下标减去1,
一个指针在每次比较的时候往后移,用于计数。
class Solution {
public:
vector sortedSquares(vector& nums) {
//双指针解法
int n = nums.size();
vector ans(n,0);
int i = 0, j = n - 1, pos = n - 1;
while(pos >= 0){
if(nums[i] * nums[i] > nums[j] * nums[j]){
ans[pos--] = nums[i]*nums[i];
i++;
}
else{
ans[pos--] = nums[j]*nums[j];
j--;
}
}
return ans;
}
};
// 时间复杂度:O(n)
// 空间复杂度:O(n)
力扣题目链接
给定一个含有 n
个正整数的数组和一个正整数
target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度**。**如果不存在符合条件的子数组,返回 0
。
经典滑动窗口思路题
也是类似于双指针的解法,定义两个指针left
和right
,分别代表滑动窗口的左右边界,同时维护一个变量sum存储子数组,也就是滑动窗口的元素之和。
left
和right
都指向0num[end]
加到sum
中sum
大于s
,说明此时可以对左边界指针也就是left
进行更新,此时获取当前最短的滑动窗口值,然后左指针不断进行移动。此时需要将已经不在滑动窗口里面的值减去class Solution {
public:
int minSubArrayLen(int target, vector& nums) {
//滑动窗口典型代表题目
int n = nums.size();
int minSize = n + 1; //初始化滑动窗口的长度为n+1
int flag = 0;
int i = 0, j = 0;
int sum = 0;
while(j < n){
sum+=nums[j++]; //右指针往后移动
while(sum >= target){ //滑动窗口总和大于target时,可以求最小滑动窗口的长度,以及更新左指针
minSize = min(j - i, minSize);
sum -= nums[i++]; //左指针不断往后移动
}
}
//三目运算符,如果滑动窗口的值没有进行改变的话,说明是不存在
return minSize == n + 1 ? 0 : minSize;
}
};
力扣题目链接
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
模拟题,这里设置了一个loop代表顺时针转了几圈,然后根据圈的数量进行模拟左右边界。
模拟顺时针画矩阵的过程:
这里有一个比较值得注意的点是,这里需要保持一个代码规划,就是左右边界的问题,每条边都需要遵循左闭右开的原则。
还有一个需要注意的就是这里loop循环一圈是单数,所以如果n为奇数的话,会剩下最后一个中间的数没有填充,所以最后面还需要判断n是否为奇数。
class Solution {
public:
vector> generateMatrix(int n) {
vector> matrix(n, vector(n));
int i = 0, j = 0, loop = 0;
int num = 1;
//螺旋矩阵,最重要的几个点,根据圈数来决定是否要结束循环
//每次循环的左右边界都需要确定好,是左闭右开,还是左闭右闭
//圈数如果为偶数,直接循环遍历,但是如果圈数为奇数的话,就需要对最里面的一个数单独赋值
while(loop < n/2){
//最上面的一行,根据圈数来决定起始位置\终止位置和每圈的个数,列在增大
for(i = loop; i < n-loop-1; i++) matrix[loop][i] = num++;
//最右边的一行,根据圈数来决定起始位置\终止位置和每圈的个数,行在增大
for(j = loop; j < n-loop-1; j++) matrix[j][n-loop-1] = num++;
//最下面的一行,根据圈数来决定起始位置\终止位置和每圈的个数,列在减小,初始值可以利用前面的i
for(;i > loop; i--) matrix[n-loop-1][i] = num++;
//最左边的一行,根据圈数来决定起始位置\终止位置和每圈的个数,行在减小,初始值可以利用前面的j
for(;j > loop; j--) matrix[j][loop] = num++;
//循环完一圈,继续下一圈
loop++;
}
//如果圈数为奇数,需要对最里面的数单独赋值
if(n % 2)
matrix[loop][loop] = num;
return matrix;
}
};
class Solution {
public:
vector> generateMatrix(int n) {
vector> matrix(n, vector(n));
//模拟,设置上下左右边界,每次遍历完某一行或者某一列,边界进行换
int num = 1;
//设置上下左右边界
int left = 0, high = 0, right = n - 1, low = n - 1;
while(true){
for(int i = left; i <= right; i++) matrix[high][i] = num++;
if(++high > low) break;
for(int j = high; j <= low; j++) matrix[j][right] = num++;
if(--right < left) break;
for(int i = right; i >= left; i--) matrix[low][i] = num++;
if(--low < high) break;
for(int j = low; j >= high; j--) matrix[j][left] = num++;;
if(++left > right) break;
}
return matrix;
}
};