数组类型题目常用解决方法
待记录
例题
leetcode59. 螺旋矩阵 II
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix
思路分析
生成一个 n×n 空矩阵 mat,随后模拟整个向内环绕的填入过程:
- 定义当前左右上下边界 l,r,t,b,初始值 num = 1,迭代终止值 tar = n * n;
- 当 num <= tar 时,始终按照 从左到右 从上到下 从右到左 从下到上 填入顺序循环,每次填入后:执行 num += 1:得到下一个需要填入的数字;
- 更新边界:例如从左到右填完后,上边界 t += 1,相当于上边界向内缩 1。 使用num <= tar而不是l < r || t < b作为迭代条件,是为了解决当n为奇数时,矩阵中心数字无法在迭代过程中被填充的问题。 最终返回 mat 即可。
class Solution {
public:
//同54题,只是该题规定是正方形,里面不必判断元素数量
vector<vector<int>> generateMatrix(int n) {
int l = 0, r = n - 1, t = 0, d = n - 1;//上下左右
vector<vector<int>> ans(n, vector<int>(n));
int total = n * n, cnt = 1;//计数:遍历多少元素了
while(cnt <= total){
//左至右(勿忘在里面判断已遍历的数量,否则长方形的矩阵会多打印)
for(int i = l; i <= r; i++) ans[t][i] = cnt++;
t++;
//上至下
for(int i = t; i <= d; i++) ans[i][r] = cnt++;
r--;
//右至左
for(int i = r; i >= l; i--) ans[d][i] = cnt++;
d--;
//下至上
for(int i = d; i >= t; i--) ans[i][l] = cnt++;
l++;
}
return ans;
}
};
其他按圈缩的解法,详见解答
leetcode54. 螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
思路分析
同上题,唯一要注意的是此处的矩阵可能是长方形,此时里面的遍历要添加元素个数的判断,否则会出现重复遍历。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();//m行n列
int l = 0, r = n - 1, t = 0, d = m - 1;//上下左右
vector<int> ans;
int total = m * n, cnt = 1;//计数:遍历多少元素了
while(cnt <= total){
//左至右(勿忘在里面判断已遍历的数量,否则长方形的矩阵会多打印)
for(int i = l; i <= r && cnt<= total; i++){
ans.push_back(matrix[t][i]);
cnt++;
}
t++;
//上至下
for(int i = t; i <= d && cnt<= total; i++){
ans.push_back(matrix[i][r]);
cnt++;
}
r--;
//右至左
for(int i = r; i >= l && cnt<= total; i--){
ans.push_back(matrix[d][i]);
cnt++;
}
d--;
//下至上
for(int i = d; i >= t && cnt<= total; i--){
ans.push_back(matrix[i][l]);
cnt++;
}
l++;
}
return ans;
}
};
其他解法详见解答
leetcode665. 非递减数列
给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。
我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。
思路
拿到今天这个题,看到是个Easy,就没有想太多了。直接判断是不是只出现了一次下降!迅速写出下面的代码,题目给的两个测试用例都通过了,那么就提交!
没想到,啪!直接来了个解答错误,很快啊! 题目说该代码没有通过测试用例 [3,4,2,3]。仔细一想还真是,虽然该数组中只出现了一次下降,但是无论调整其中的一个数字都不能得到一个单调上升的数组。
那么,这题就有讲究了。下面我举了例子,相信我,下面的分析不难,你看完一定能懂。举例分析
首先,看下面的几个测试用例,它们都因为数字 2 的出现,导致数组是非单调递增的。
例①: 4, 2, 5 例②: 1, 4, 2, 5 例③: 3, 4, 2, 5
当数组中出现 2时,破坏了数组的单调递增。为了让数组有序,我们需要对 2 或者 4 进行调整:
第①个用例,我们可以 把 4 调小到 <= 2 或者 把 2 调大到 4、5 ,使数组有序。 第②个用例,我们可以 把 4 调小到 1、2或者 把 2 调大到 4、5 ,使数组有序。 第③个用例,我们必须 把 2 调大到 4、5,才能使数组有序:我们不能把 4 调整为一个 <=2 的数字,因为 4 前面的元素是 3.
归纳总结
当 nums[i] 破坏了数组的单调递增时,即 nums[i] < nums[i - 1] 时,为了让数组有序,我们发现一个规律(在上面三个例子中, nums[i] 都为 2, nums[i -1] 都为 4):如例①的情况,当 i = 1 ,那么修改 num[i- 1] ,不要动 nums[i],因为nums[i]后面的元素是啥我们还不知道呢,少动它为妙。 如例②的情况,当 i > 1 时,我们应该优先考虑把 nums[i - 1]调小到 >= nums[i - 2] 并且 <= nums[i]。同样尽量不去修改 nums[i] ,理由同上。 如例③的情况,当 i >1 且 nums[i] < nums[i - 2] 时,我们无法调整 nums[i - 1] ,我们只能调整 nums[i] 到nums[i - 1] 。
找到nums[i-1]>当前nums[i]时,也要判断前第二个数nums[i-2]与当前数nums[i]的大小关系
class Solution {
public:
bool checkPossibility(vector<int>& nums) {
int n = nums.size(), count = 0;
for(int i = 1; i < n; i++){
if(nums[i - 1] > nums[i]){//出现前一个>后一个数时
if(i == 1 || nums[i - 2] <= nums[i]){//勿忘判断当前数与往前两个数的大小关系
nums[i - 1] = nums[i];
}else{
nums[i] = nums[i - 1];
}
count++;//找到一个降序对就+1
}
}
return count <= 1;
}
};
另一个思路
或者 不赋值直接 依然统计降序对个数,只是把特殊情况单独写出来判断
- 遍历数组,初始count = 0,如果当前元素值比它下一个元素值大,则count += 1,当count > 1时,直接返回false。
- 另外,在遍历数组的过程中,如果遇到 “特殊情况”,可以直接返回false;当循环正常结束则返回true。
特殊情况解释:
首先看一个简单的例子:[2, 4, 0, 1]
当下标 i == 2 时,nums[i] < nums[i-1],也就是 0 < 4,这时我们要保证数组非递减有两种选择:
选择 1:把 0 放大,并且保证 0 后面的数不能比 4 小,0 前面的数均是非递减的;
选择 2:把 4 缩小,并且保证 4 前面的数不能比 0 大,4 后面的数均是非递减的。
换言之,当 0 < 4时,如果以上两个选择中的保证同时不满足,说明该数组肯定无法通过只修改一个元素而变为非递减数组,该情况即为上述提到的 “特殊情况”。对于本例,有:当 0 < 4时,0 后面的数为 1,1 小于 4,不满足选择 1 的保证;且 4 前面的数为 2,4 后面的数为 0,0 小于 2,不满足选择 2 的保证。
综上,我们可以把 “特殊情况” 归纳为:
if nums[i] < nums[i-1]: # 当 0 < 4 时
if nums[i+1] < nums[i-1] and nums[i-2] > nums[i]: # 1 < 4 and 2 > 0
return False # 不用继续遍历,可直接返回false
另外需要注意数组下标不要越界。
完整代码:
class Solution:
def checkPossibility(self, nums: List[int]) -> bool:
count = 0
for i in range(1,len(nums)):
if nums[i] < nums[i-1]:
count += 1
if i+1 < len(nums) and i-2 >= 0:
if nums[i+1] < nums[i-1] and nums[i-2] > nums[i]:
return False
if count > 1:
return False
return True