977.有序数组的平方
题目描述:
返回给定有序数组各个元素的平方(有序)。
思路:
因为给定数组中可能包含负数,因此平方后,结果集中最大的数值在原数组的两端。
利用这一特征,可以使用双指针
从原数组两端进行遍历
比较平方值较大的先添加
依从大到小的顺序将结果逆序加入结果数组
难点:
双指针
边界条件i=j
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length];
int idx = nums.length-1;
int i = 0;
int j = nums.length-1;
while (i<=j) {
if (Math.pow(nums[i],2) > Math.pow(nums[j],2)) {
res[idx--] = nums[i]*nums[i];
i++;
}else {
res[idx--] = nums[j]*nums[j];
j--;
}
}
return res;
}
}
时长:
15min
收获:
参考代码随想录的代码,发现for循环条件中的第三项是可以省略的~~~
class Solution {
public int[] sortedSquares(int[] nums) {
int[] result = new int[nums.length];
int k = nums.length-1;
for (int i=0, j=nums.length-1; i<=j;) {
if (nums[i]*nums[i] <= nums[j]*nums[j]) {
result[k--] = nums[j]*nums[j];
j--;
}else {
result[k--] = nums[i]*nums[i];
i++;
}
}
return result;
}
}
209. 长度最小的子数组
题目描述:
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
思路:
暴力
时间复杂度:O(n^2)
空间复杂度:O(1)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int minLen = Integer.MAX_VALUE;
int sum;
for (int i = 0; i < nums.length; i++) {
sum = 0;
for (int j = i; j < nums.length; j++) {
sum += nums[j];
if (sum >= target && (j-i+1) < minLen) {
minLen = j-i+1;
break;
}
}
}
return minLen == Integer.MAX_VALUE? 0 : minLen;
}
}
没通过,超时了。。。
思路:
使用滑动窗口(仅用一个for循环来遍历子序列的终止位置)
时间复杂度:O(n)
空间复杂度:O(1)
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int minLen = Integer.MAX_VALUE;
int sum = 0;
int i = 0;
for (int j = 0; j < nums.length; j++) {
sum += nums[j];
while (sum >= target) {
minLen = Math.min(j - i + 1, minLen);
sum -= nums[i++]; //滑动窗口的精髓
}
}
return minLen == Integer.MAX_VALUE? 0 : minLen;
}
}
时长:
30min
收获:
如何使用滑动窗口。
59. 螺旋矩阵 II
题目描述:
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
思路:
求解本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
难点:
注意当n为奇数时,中间元素不要遗漏。
时间复杂度:O(n)
空间复杂度:O(n^2)
class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
int loop = 0;
int start = 0;
int count = 1;
int i, j;
while (loop++ < n/2) {
//从左到右
for (j = start; j < n-loop; j++) {
matrix[start][j] = count++;
}
//从上到下
for (i = start; i < n-loop; i++) {
matrix[i][j] = count++;
}
//从右到左
for (j = n-start-1; j > start; j--) {
matrix[i][j] = count++;
}
//从下到上
for (i = n-start-1; i > start; i--) {
matrix[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
matrix[n/2][n/2] = n*n;
}
return matrix;
}
}
因为loop
和start
是挂扣的,因此代码可以进一步精简(首先保证写出,然后再优化)
class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
int loop = 0;
int count = 1;
int i, j;
while (loop++ < n/2) {
//从左到右
for (j = loop-1; j < n-loop; j++) {
matrix[loop-1][j] = count++;
}
//从上到下
for (i = loop-1; i < n-loop; i++) {
matrix[i][j] = count++;
}
//从右到左
for (j = n-loop; j > loop-1; j--) {
matrix[i][j] = count++;
}
//从下到上
for (i = n-loop; i > loop-1; i--) {
matrix[i][j] = count++;
}
if (count >= n*n) {
break;
}
}
if (n % 2 == 1) {
matrix[n/2][n/2] = n*n;
}
return matrix;
}
}
代码随想录的代码示例:
class Solution {
public int[][] generateMatrix(int n) {
int loop = 0; // 控制循环次数
int[][] res = new int[n][n];
int start = 0; // 每次循环的开始点(start, start)
int count = 1; // 定义填充数字
int i, j;
while (loop++ < n / 2) { // 判断边界后,loop从1开始
// 模拟上侧从左到右
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
}
// 模拟右侧从上到下
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
}
// 模拟下侧从右到左
for (; j >= loop; j--) {
res[i][j] = count++;
}
// 模拟左侧从下到上
for (; i >= loop; i--) {
res[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
res[start][start] = count;
}
return res;
}
}
时长:
20min
收获:
耐心细心,把握边界。
for循环中,可以省略部分条件项。