1. 有序数组的平方
第一个想法就是暴力写法,把所有的数平方再排序,太容易实现了,直接跳过
- 时间复杂度:O(n + nlog n)
双指针法
昨天用过双指针法,今天自己写的时候就很有感觉,没费什么时间稍微Debug了下就搞定了。
左右各一个指针,对应的数平方后比大小,大的数就是rs[]的最后一位。
然后该指针移动,继续比较两个指针对应数的平方,大的数就是rs[]的倒数第二位。
以此类推……
class Solution {
public int[] sortedSquares(int[] nums) {
int size = nums.length;
int[] rs = new int[size];
int left = 0;
int right = size - 1;
int rs_right = size - 1;
while(left <= right){
if(nums[left] * nums[left] > nums[right] * nums[right]){
rs[rs_right] = nums[left] * nums[left];
left++;
}
else{
rs[rs_right] = nums[right] * nums[right];
right--;
}
rs_right--;
}
return rs;
}
}
2.长度最小的子数组
一上来还是只想到了暴力解法,双指针考虑了一会,好像也不行,因为写着写着就成了暴力解法了
稍微看了下卡哥给的思路,看到了“滑动窗口”,好吧,没用过的新方法
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//暴力解法
int size = nums.length;
int lengthMin = size + 1;
int sum = 0;
for(int i = 0; i < size; i++){
sum = 0;
for(int j = i; j < size; j++){
sum+=nums[j];
if(sum >= target){
lengthMin = j-i+1 < lengthMin? j-i+1:lengthMin;
break;
}
}
}
return lengthMin <= size? lengthMin:0;
}
}
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
看完了视频讲解的思路,自己写了下
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int size = nums.length;
int lengthMin = size + 1;
int sum = 0;
int i = 0;
for(int j = 0; j < size; j++){
sum += nums[j];
while(sum >= target){
lengthMin = j-i+1 < lengthMin? j-i+1: lengthMin;
sum -= nums[i++];
}
}
return lengthMin <= size? lengthMin:0;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
一些录友会疑惑为什么时间复杂度是O(n)。
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
-- 代码随想录
其中 j 是终点,i 是根据情况移动的起点
j 从开始遍历数组,将它所遍历的数全部相加,当和大于等于target时,暂停向后遍历
此时减去 i 所指向的数,并判断sum是否仍然大于等于target,若大于则继续移动 i 并减去对应的数,否则用 j 从暂停的地方继续遍历
这个思路就像一个窗口一样,通过滑动一端,来使窗口内的数符合目标,再通过滑动另一端微调窗口,使得窗口内的数更优。就这样通过滑动窗口的两端,使得窗口遍历过所有符合target的集合,从而找出最优解。
3.螺旋矩阵II
看似很简单的一道题,绕了我半天跑出来还是一堆问题,最后看讲解,按照自己的理解写出来了。
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int count = 1;
int loop = 0;
int i,j; //[i][j]
//[)
while(loop < n/2){
// → i不变,j变
for(j = loop; j < n-1-loop; j++){
nums[loop][j] = count++;
}
// ↓ j不变,i变
for(i = loop; i < n-1-loop; i++){
nums[i][j] = count++;
}
// ← i不变,j变
for(; j > loop; j--){
nums[i][j] = count++;
}
// ↑ j不变,i变
for(; i > loop; i--){
nums[i][j] = count++;
}
loop++;
}
if (n % 2 == 1) {
nums[loop][loop] = count;
}
return nums;
}
}
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
因为转一圈少两行两列,那么n行×n列的矩阵,只能循环 n/2 次,故 loop 从0开始要小于 n/2;
循环的总规则:[) 即不处理一行或一列得最后一个元素,交给变向后处理。
对于一个二维数组 [ i ][ j ] 对应的二维矩阵
[1,2,3] [8,9,4] [7,6,5]
横向移动:i 不变,j 变
纵向移动:j 不变,i 变
其中,循环次数越多,在每条边上需要移动的次数就越少,
每循环一次,它的出发点和终点都会随循环次数增加1,而随之减少1。
(具体的过程有点难用文字表达清楚)
最后当n为奇数时,中间会留一个数,需要再单独处理一下。