代码随想录算法训练营第2天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

数组理论基础

文章链接:https://programmercarl.com/%E6%95%B0%E7%BB%84%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

977.有序数组的平方

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/description/

思路1.暴力排序

将每个数平方之后,直接排序

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;
    }
}

时间复杂度 O(n + nlogn)

思路2.双指针法

注意这里数组是有序的,只不过在负数平方之后,有可能会变成最大数。
那么数组平方后的最大值,要么是在最左边,要么就是在最右边。
这里的话,我们就可以使用双指针,i指向起始位置,j指向终止位置。
然后,定义一个新的数组,和A数组同样的大小,让k指向result数组的终止位置(因为我们接收的数字是从大到小)

  • 如果A[i] * A[i] < A[j] * A[j],那么result[k–] = A[j] * A[j];
  • 如果A[i] * A[i] >= A[j] * A[j] 那么result[k–] = A[i] * A[i];
class Solution {

    // 默认是有序的
    public int[] sortedSquares(int[] nums) {
      int i = 0;
      int j = nums.length-1;
      int[] result = new int[nums.length];
      int k = j;
      while(k>=0)
      {
          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;
    }
}

时间复杂度 O(n),比暴力解法提升了很多

209.长度最小的子数组

题目连接:https://leetcode.cn/problems/minimum-size-subarray-sum/

解法1:暴力解法(遍历所有可能的子序列)

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

时间复杂度O(n^2)

解法2:滑动窗口

用一个for循环,如何表示滑动窗口的起始位置,还是终止位置。
假如我们用一个for循环,来表示滑动窗口的起始位置,那么遍历剩下的终止位置,又会陷入了暴力解法之中。
因此,这个循环的索引,只能是表示滑动窗口的终止位置。
那么,滑动窗口的起始位置如何移动,需要我们进行考虑。
具体见动画演示
代码随想录算法训练营第2天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II_第1张图片

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int len = nums.length;
        int i = 0;
        int sum = 0;
        int result = 9999999;
        for(int j=0;j<len;j++){
            sum = sum + nums[j];
            while(sum>=target){
                result = Math.min(result,j-i+1);
                sum -= nums[i];
                ++i;
            }
        }
        if(result==9999999) result = 0;
        return result;
    }
}

时间复杂度:O(n),不要以为for里放一个while就以为是O(n^2), 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

#相关题目推荐

59.螺旋矩阵II

题目连接:https://leetcode.cn/problems/spiral-matrix-ii/

解法:模拟过程

本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。
求解本题依然是要坚持循环不变量原则。
我们模拟顺时针画矩阵的过程,由外向内一圈一圈的画下去,这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
这里我们按照左闭右开的原则。
代码随想录算法训练营第2天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II_第2张图片

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

然后就是还要注意一个点,当n为奇数的时候,中间会多出一个方块,单独赋值即可。

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] a = new int[n][n];
        // 定义起始点
        int startx = 0,starty=0;
        // 循环次数
        int loop = n/2;
        int offset = 1;
        int i,j;
        int count = 1;
        // 左闭右开的原则
        while(loop-- > 0)
        {   
            i=startx;j=starty;
            // 最上面
            for(j=starty;j<n-offset;j++){
                a[i][j] = count++;
            }
            // 右边(此时i=n-offset了)
            for(i=startx;i<n-offset;i++){
                a[i][j] = count++;
            }
            // 下边(此时i,j在最下角)
            for(;j>starty;j--)
                a[i][j] = count++;
            for(;i>startx;i--)
                a[i][j] = count++;
            
            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            ++startx;
            ++starty;
            // 控制每一圈里遍历的长度,例如第一圈是n-1,第二圈就是n-2
            ++offset;
          
        }
        
        if(n%2!=0)
            a[n/2][n/2] = count; 
        return a;
        
        
        
    }
}

时间复杂度:O(n^2)
空间复杂度:O(1)

你可能感兴趣的:(算法,矩阵,线性代数)