有序数组的平方:977. 有序数组的平方 - 力扣(LeetCode)
https://leetcode.cn/problems/squares-of-a-sorted-array/
解题思路:
- 暴力解法:遍历数组使每个元素平方再用sort排序,时间复杂度为O(nlogn)取决于sort快速排序的时间复杂度
具体代码 如下:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0;i < nums.size();i++){
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(),nums.end());
return nums;
}
};
- 双指针解法: 已知数组是非递减的有序数组,也就是说是从小到大的顺序,但是数组中不排除负数,所以所有数平方之后数组就会呈现中间小两边大的顺序,也就是说最大数要么在左边要么在右边,将两个指针i和j分别指向数组的开头和结尾并将两个指针向中间移动靠拢,再定义一个新数组来存放结果,只要 i<=j 就让 nums[i]^2 和 nums[j]^2 比较,大的放入新数组的最后一个位置。
具体代码如下:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int len = nums.size();
int i = 0,j = len - 1;//将两个指针分别放在数组的开头和结尾
vector<int>arr(nums.size(),0);
int k = len - 1;
while(i <= j){//将两个指针分别向中间靠拢
if(nums[i] * nums[i] > nums[j] * nums[j]){
arr[k--] = nums[i] * nums[i];
i++;//两数平放相比先将大数放入这个新数组的后面
}else{//如果两个数的平方相等那么不管先将哪个数放进去都一样
arr[k--] = nums[j] * nums[j];
j--;
}
}
return arr;
}
};
长度最小的子数组: 209. 长度最小的子数组 - 力扣(LeetCode)
https://leetcode.cn/problems/minimum-size-subarray-sum/description/
解题思路:
- 暴力解法:先将result赋予一个最大值,用两层 for 循环,i 表示起始位置,j 表示终止位置,用第一层 for 循环遍历数组,第二层 for 循环将数组起始位置到终止位置的和求出与 target 比较,若大于等于 s 就将从起始位置到终止位置的长度记录下来赋给 len ,比较 len 和 result 大小,将小的赋给 result。最后如果result还等于初始值就返回0,否则就返回result。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT_MAX;
int sum = 0,len = 0;
for(int i = 0;i < nums.size();i++){//i表示起始位置下标
sum = 0;
for(int j = i;j < nums.size();j++){//j表示终止位置下标
sum += nums[j];
if(sum >= target){
len = j - i + 1;//子序列和超过sum之后就将此时子序列的长度记录下来
result = result > len ? len : result;//更新result的值
break;//一旦找到符合条件的最短子序列,就跳出循环
}
}
}
return result == INT_MAX ? 0 : result;
}
};
//因为力扣的数据库更新,此方法已超出时间限制
- 滑动窗口解法 :滑动窗口就是不断调节子序列的起始位置和终止位置,先将起始位置暂时定住,用 j 表示终止位置,遍历数组将 j 指向的元素依次相加得到一个和,只要和大于等于target,就将j此时指向元素到其实元素的长度记录下来,与最大值 result 比较,小的那个赋给result 并将得到的和中的起始位置指向的元素减去,将 i 移动到下一位,最后返回被赋值后的result。
具体代码如下:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT_MAX;
int sum = 0,len = 0,i = 0;
for(int j = 0;j < nums.size();j++){
sum += nums[j];
while(sum >= target){
len = j - i + 1;
result = result > len ? len : result;
sum = sum - nums[i++]; //改变窗口的起始位置,只要和是大于等于指定数字的就将i指向元素删去
}
}
return result == INT_MAX ? 0 : result;
}
};
温馨提示:如果看完代码还不明白可以调试一下看看具体过程,也可以自己在纸上倒腾一遍,大家加油!
相关题目:904、76
螺旋矩阵:
59. 螺旋矩阵 II - 力扣(LeetCode)https://leetcode.cn/problems/spiral-matrix-ii/description/
解题思路:
这个题使用的思想是循环不变量的思想,也就是先定位号自己的区间是左闭右闭还是左闭右开,这点与二分查找 中使用的思想很相似,在螺旋矩阵这里我们采用左闭右开的思想,将矩阵每行或每列的最后一个点交给相邻的列或行。还有一点就是矩阵n是奇数还是偶数,如果是奇数,这种左闭右开的形式势必会使中间的一个坐标为行标和列表相等(nums[n][n])的位置空出来,所以当n是奇数时,单独给中间空出来的赋值。
具体代码如下:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>>nums(n,vector<int>(n,0));
int startx = 0,starty = 0;
int mid = n / 2;//如果n为奇数,mid表示最中间那个
int loop = n / 2;//代表要转的圈数
int offest = 1;//表示每条边要遍历的长度,每条边缩进一位
int count = 1;//每位要填的数
while(loop--){
int i = startx,j = starty;
for(j = starty;j < n - offest;j++){//首先是要填的矩阵行不变,列增加
nums[i][j] = count++;
}
for(i = startx ; i < n - offest;i++){//列不变,行增加
nums[i][j] = count++;
}
for(j = n - offest;j > starty;j--){
nums[i][j] = count++;
}
for(i = n - offest;i > startx;i--){
nums[i][j] = count++;
}
startx++;//每转一圈,起始值都会加1
starty++;
offest++;//每转一圈,缩进的位数就增加1
}
if(n % 2 != 0){
nums[mid][mid] = count;
}
return nums;
}
};
//本题主要考察的其实没有什么算法,就是模拟转圈的过程,本题时顺时针填数,大家可自行试一下逆时针。
相关题目:54、29
算法训练第二天,感觉稍微有一点吃力,继续加油!