3. 有序数组的平方
题目链接:977. 有序数组的平方 - 力扣(LeetCode)
思路一:排序
很容易想到的思路:平方后,在排序即可
- 时间复杂度:取决于排序的复杂度,
O(nlogn)
- 空间复杂度:
O(1)
Code
class Solution {
public int[] sortedSquares(int[] nums) {
for(int i = 0; i < nums.length; i ++){
nums[i] = nums[i] * nums[i];
}
Arrays.sort(nums);
return nums;
}
}
思路二:双指针
由于之前的nums
数组是递增
的,那么平方后最大数必定会在两侧中的某一侧,如 -10 1 1 1 2 5
,即要么完全递增,要么从两侧向中间逐渐递减(二段单调性!),为此就可以使用双指针来进行优化。我们还需要一个额外的数组result
空间来记录答案,由于是先拿到最大数,我们就得从result
右到左放置答案。
- 时间复杂度:
O(n)
- 空间复杂度:
O(n)
Code
class Solution {
public int[] sortedSquares(int[] nums) {
int n = nums.length;
int[] result = new int[n];
int k = n - 1;
// -10 1 1 1 2 5
int i = 0, j = n - 1;
while(i <= j){
if(nums[i] * nums[i] >= nums[j] * nums[j]){
result[k --] = nums[i] * nums[i];
i ++;
}else {
result[k --] = nums[j] * nums[j];
j --;
}
}
return result;
}
}
4. 长度最小的子数组
题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
思路一:暴力枚举
两次循环找到连续和大于等于target
的最小连续子段即可
- 时间复杂度:
O(n*n)
- 空间复杂度:
O(1)
Code
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int res = Integer.MAX_VALUE;
for(int i = 0; i < n; i ++){
int sum = 0;
for(int j = i; j < n; j ++){
sum += nums[j];
if(sum >= target){
res = Math.min(res, j - i + 1);
break;
}
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
思路二:滑动窗口
我们发现,找连续和大于等于target
的最小连续子段,其实就是维护一个sum
的窗口,窗口的右边界j边移动 sum就加上相应的值 使得窗口和增大
,当窗口里边数的和sum>=target
此时就可以更新答案了,然后左边界i一直 ++ sum减去相应的值 直到窗口值不再 >= target
。如此往复,直到j
到达末尾。
- 时间复杂度:
O(n)
- 空间复杂度:
O(1)
Code
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int res = Integer.MAX_VALUE;
// i:窗口左边界 j:窗口右边界
int i = 0, j = 0;
// sum:动态维护窗口的和
int sum = 0;
while(j < n){
sum += nums[j ++];
while(sum >= target){// 注意:这里是while
res = Math.min(res, j - i);
sum -= nums[i ++];
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
5. 螺旋矩阵 II
题目链接:59. 螺旋矩阵 II - 力扣(LeetCode)
通过控制方向来模拟填数,有点像我们dfs或者bfs那种棋盘四方向
或者八方向
扩展的题目
参考链接:螺旋矩阵 II | 模拟解法,代码简洁易懂 【c++/java版本】 - 螺旋矩阵 II - 力扣(LeetCode)
Code
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
// 右下左上
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
int x = 0, y = 0;// 当前位置
// d用来控制方向:0 1 2 3
// 右 下 左 上
for(int i = 1, d = 0; i <= n * n; i ++){
res[x][y] = i;// 填数
int a = x + dx[d], b = y + dy[d];// 下一步
if(a < 0 || a >= n || b < 0 || b >= n || res[a][b] != 0){ //出界或者该位置已经被走过
d = (d + 1) % 4;// 更改方向
a = x + dx[d];
b = y + dy[d];
}
x = a;
y = b;
}
return res;
}
}
总结:还是只有暴力解题的思想,看了视频讲解和相关题解后自己写了一遍,还是花些时间的