977 有序数组的平方
-
题目描述
- 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
- 示例 1:
- 输入:nums = [-4,-1,0,3,10]
- 输出:[0,1,9,16,100]
- 解释:平方后,数组变为 [16,1,0,9,100]排序后,数组变为 [0,1,9,16,100]
- 示例 2:
- 输入:nums = [-7,-3,2,3,11]
- 输出:[4,9,9,49,121]
-
暴力法
- 先平方,对新的数组进行排序;
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//对原数组全部平方
for (int i = 0; i < nums.size(); i++) {
nums[i] = pow(nums[i], 2);
}
//对平方后的数组进行排序
for (int i = 0; i < nums.size(); i++) {
for (int j = i + 1; j < nums.size(); j++) {
if (nums[j] < nums[i]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
return nums;
}
};
-
双指针思路
- 平方之后大元素在两边,小元素在中间
- 一个指针(j)指向数组尾,一个指针(i)指向数组首,对比平方大小,将对应位置的元素平方放到新的Results数组中
- for( int i = 0; j = numsize-1; i<=j ): j往前走,i往后走,直至相遇遍历完整个数组,且条件为 i <= j;相遇的时候也要将相遇的元素放到Results数组中,防止漏元素;
- j往前走,即j对应的平方值比较大,所以去j对应的位置j--;
- i往后走,即i对应的平方值比较大,所以去i对应的位置i++;
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int k = nums.size() - 1;
vector<int> results(nums.size(), 0);
for (int i = 0, j = nums.size()-1; i <= j ;) {
if (pow(nums[i], 2) <= pow(nums[j], 2)) {
results[k--] = pow(nums[j], 2);
j--;
}
else{
results[k--] = pow(nums[i], 2);
i++;
}
}
return results;
}
}:
23 长度最小的子数组
-
题目描述
- 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
- 示例 1:
- 输入:target = 7, nums = [2,3,1,2,4,3]
- 输出:2
- 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
- 示例 2:
- 输入:target = 4, nums = [1,4,4]
- 输出:1
- 示例 3:
- 输入:target = 11, nums = [1,1,1,1,1,1,1,1]
- 输出:0
-
暴力解法
- 两次for循环,第一个for循环遍历数组的各个元素,第二个for循环从当前元素开始累加直至数组总和达到目标值,进行统计。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;//result 为结果长度,先置为最大数
int numslength = 0;//当前统计的长度
int sum;
for (int i = 0; i < nums.size(); i++) {
sum = 0;//每次循环开始sum重置为零
for (int j = i; j < nums.size(); j++) {
sum += nums[j];
//判断,得到由i对应数字开始的总和能过大于s的最短数组
if (sum >= s) {
numslength = j - i + 1;//取满足条件的序列的长度
if (numslength < result) result = numslength;
break;//找到满足的数组即可停止循环
}
}
}//result是否更新了,更新了则说明找到了最短序列,没更新则说明没有找到,则输出结果为零;
return result == INT32_MAX ? 0 : result;
}
};
-
双指针法
- 一个for循环实现两个for循环的工作,滑动窗口;
- 关键在于滑动窗口的动态移动,首先明确j对应的是滑动窗口的尾部,通过for循环遍历数组,使其每一个数字都成为过滑动窗口的尾部。
- sum -= nums[i++];//关键之处,即在满足sum已经足够的情况下,从首部i往后移动进行缩减,使得滑动窗口尽可能的小;
- 在不满足循环条件即sum >= s 时,窗口的尾部即 j 开始往右边滑动,满足条件窗口首部即i再开始往右边滑动,对滑动窗口进行缩减;
- 如此反复便可以得到数组的每个尾部j所对应最小的子数组,进行比较得到对于整个数组来说长度最小的子数组;
class Solution {
public:
//最好结合动画理解滑动过程
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int numslength = 0;
int i = 0;//i 是滑动窗口的首位置
for (int j = 0; j < nums.size(); j++) {// j是滑动窗口的尾部
sum += nums[j];
while (sum >= s) {
numslength = j - i + 1;
if (numslength < result) result = numslength;//更新result
sum -= nums[i++];//关键之处,即在满足sum已经足够的情况下,从首部i往后移动进行缩减,使得滑动窗口尽可能的小
}
//在不满足循环条件即sum >= s 时,窗口的尾部即 j 开始往右边滑动,满足条件窗口首部即i再开始往右边滑动
//如此反复便可以得到数组的每个尾部j所对应最小的子数组;进行比较得到对于整个数组来说长度最小的子数组
}
return result == INT32_MAX ? 0 : result;
}
};
59 螺旋矩阵II
-
题目描述
- 给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
- 示例:
- 输入: 3
- 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
-
重点
- 本题涉及到与二维数组相关的循环,相较于一维数组,虽然复杂度提高了,但依然存在着明显的规律:正方形每层外壳都是按照1,2,3,4四个方向进行旋转的,而每次的旋转也都是按照一定的节点来推进的。
- 循环的次数:loop = 矩阵半径/2;即转多少次圈圈;偶数自然是除以二(每一圈占两个格子)奇数最中间的那个是数字n,剩下的自然就是偶数辣,同理;
- 左闭右开:int offset = 1;offset为当前循环离边界的距离,初始为1;例如4*4,第一行只能到0,1,2;3就已经算竖向的;因此第一次是3格*4,第二次是1格*4;每次转圈左边一格,右边一格,上边一格,下边一格,转完一圈之后offset+1;通过n-offset找到每次循环最终格子值:第一圈是4-1=3,临界格子序号是3;第二圈offset+1之后,n-offset是2即临界格子序号是2;以此类推循环;
- startx,starty:为横纵坐标的起点,每次转圈完+1;
- 每一圈是四个方向即四个循环:第一次循环for (j = starty; j < n - offset; j++) {nums[startx][j] = count++;}//也可以是nums[i][j] = count++;每次循环完之后i,j回到的点为新的startx,starty是一样的;每次循环的关键点在于左边界,右边界;即startx/y和offset-n;
- 本题涉及到与二维数组相关的循环,相较于一维数组,虽然复杂度提高了,但依然存在着明显的规律:正方形每层外壳都是按照1,2,3,4四个方向进行旋转的,而每次的旋转也都是按照一定的节点来推进的。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>>nums(n, vector<int>(n, 0));//定义一个n*n二维空数组
int startx = 0;
int starty = 0;
int loop = n / 2;//偶数自然是除以二(每一圈占两个格子)奇数最中间的那个是数字n,剩下的自然就是偶数辣,同理;
int offset = 1;//左闭右开,例如4*4,第一行只能到0,1,2;3就已经算竖向的循环了
int count = 1;
int i;
int j;
while (loop--) {
i = startx;//每次循环开始的横行,循环完一次后++
j = starty;//每次循环开始的纵行,循环完一次后++
//满足每一个遍历都是左闭右开
//第一次从左上到右上,横坐标i不变,纵坐标j++;
for (j = starty; j < n - offset; j++) {
nums[i][j] = count++;//先计数,再递增
}
//从右上到右下,纵坐标为刚才的j不变,横坐标i++;
for (i = startx; i < n - offset; i++) {
nums[i][j] = count++;
}
//从右下到左下,横坐标不变为刚才的i;纵坐标j--;
for (; j > starty; j--) {
nums[i][j] = count++;
}
//从左下到左上,纵坐标不变为刚才的j;横坐标i--;
for (; i > startx; i--) {
nums[i][j] = count++;
}
offset++;
startx++;
starty++;
}
//如果是奇数,勿忘中心
if (n % 2) {
nums[n / 2][n / 2] = count;
}
return nums;
}
};
总结&&碎碎念
题做了,笔记也写了,就是没有腾到博客上,拖延症啊拖延症……上周周四周五不少课,周六周日一边忙一边玩,刷题耽搁了两天,得速速补上。至于博客,一开始比较习惯用幕布来记录要点,比较清晰,但是转到CSDN的博客上面还是有点小麻烦,不过做过一两次还是清晰了不少流程(还是得吐槽CSDN这个编辑撤回Crtl+Z,Tab键,分级标题和正文之间的切换,是我不习惯还是说本身就很难用呢~)
任务还是很重的,为了理想的目标和自己,得加把劲了(记得要补一下数组的总结~)