977.有序数组的平方
题目内容:给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
我的代码:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int& it : nums) { //使用引用‘it’迭代每个元素
it = it * it; //并对引用进行平方处理
}
sort(nums.begin(), nums.end()); //使用'sort()'函数对数组进行升序处理
return nums;
}
};
反思:自己做题时,对于可以使用引用来迭代每个元素并对每个元素进行相同操作这一部分还不是很熟练,要加强cpp语法学习。
209.长度最小的子数组
题目: 给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
我的代码:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int l = 0, r = 0;
int sum = nums[l];
int min_len = INT_MAX;
while(r < nums.size()) {
if(sum >= target) {
min_len = min(min_len, r-l+1); //使用一个变量不断地更新
//来记录最小子数组的长度
sum -= nums[l];
l++;
}else if(sum < target) {
r++;
if(r < nums.size()) { //第一次做题时忘记检查r的边界条件了
sum += nums[r];
}
}
}
return min_len == INT_MAX ? 0 : min_len;
}
};
反思:第一次做题时,不懂得用一个不断变化的变量记录最小子数组长度,可能导致最后取到的子数组总是靠数组最右侧的(只是猜测,没有实际模拟过);还有碰到数组忘记检查是否越界,不止这道题,自己平时做题也经常忘记检查边界条件;利用INT_MAX这一最大值初始化min_len,一个数组的长度无论如何都小于INT_MAX,如果不存在这样的子数组min_len也不会取nums.size(),这一做法对我来说也很新奇,需要多多熟悉。
总结了一下边界条件检查:
除了数组下标越界和栈空,还有以下容器的边界条件需要检查:
-
队列空:在尝试从队列中取出元素之前,需要确保队列不为空,否则可能导致空队列的错误。
-
迭代器是否有效:在使用迭代器访问容器元素之前,应该确保迭代器仍然有效,否则可能导致未定义行为。
-
指针是否为 null:在使用指针访问容器元素之前,应该确保指针不为空,否则可能导致空指针解引用错误。
-
集合是否为空:在尝试从集合中取出元素之前,应该确保集合不为空,否则可能导致空集合的错误。
-
映射中是否存在键:在尝试使用键来访问映射中的值之前,应该确保键存在于映射中,否则可能导致键不存在的错误。
-
容器是否满:对于一些固定大小的容器(例如固定大小的队列或堆栈),在尝试向容器中添加元素之前,应该确保容器尚未满,否则可能导致容器溢出的错误。
-
数组下标是否越界:在对数组下标进行操作前后,应该确保数组下标没有越界,否则可能导致数组下标越界的错误。
59.螺旋矩阵II
题目:给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 :
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]
我的代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> a(n, vector<int>(n, 0)); //要使用一维数组来初始化二维数组
int hang = 0, lie = 0, i = 0, j = 0, cnt = 1, m = n/2;
//hang、lie分别用来记录当前循环从哪一行哪一列开始,i、j用来跟进,往数组中装元素
//循环停止条件:每走完一圈,螺旋的上下左右长度都-1,相当于长-2,宽-2,
//每循环完一圈长宽都-2,直到长宽为0时循环结束,循环次数就是n/2
while(m) {
for(j = lie; j < n-lie-1; j++) {
a[hang][j] = cnt++;
}//j要在当前循环圈的末尾位的前一个停止,末尾位交给下一个循环的开头,所谓“左闭右开”
//区间一致是本题的一个重要原则,我在这里选择了“左闭右开”,那么贯穿全题都是左闭右开
for(i = hang; i < n-hang-1; i++) {
a[i][j] = cnt++;
}
for( ; j > lie; j--) {
a[i][j] = cnt++;
}
for( ; i > hang; i--) {
a[i][j] = cnt++;
}
hang++;
lie++;
m--;
}
if(n%2 == 1) {
a[hang][lie] = n * n;
}//奇数个的时候,不要忘了最中间
return a;
}
};
反思:第一次做的时候循环停止条件写的不对,用的while(cnt <= n*n),这会导致增添了很多轮不必要的轮数从而导致超时,实际上这是一个“画圆圈”的循环,循环次数就是要画的圈数,还有本题很重要的“区间一致”原则,选择了“左闭右开”就要将左闭右开贯彻到底;代码的主体部分我借助了图,从而对代码运行和边界条件更加清晰。
总结:这三道题我大约两三星期前做过一遍,那个时候看2、3题还属于一脸懵的状态,经过了几次温习,我了解了滑动窗口,看到了新颖的循环题型,也对循环、引用有了一个更深的了解。