第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

/**
 * 2023/12/28 第二天 T1
 * 977.有序数组的平方
 */
	//暴力: o(n*logn)
    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)
    public int[] sortedSquares2(int[] nums) {
        int i = 0,j = nums.length - 1,k = nums.length - 1;
        int[] newNums = new int[nums.length];
        for (i = 0; i < nums.length; i++) {
            nums[i] = nums[i] * nums[i];
        }
        i = 0;
        //双指针(类似归并中合并两个有序序列)
        while (i <= j){ //要带等于,否则会漏掉一个元素!
            if (nums[i] > nums[j]) newNums[k--] = nums[i++];
            else newNums[k--] = nums[j--];
        }
        return newNums;
    }
  • 看到题目就想先平方求新数组,然后新数组调Arrays.sort(newNums) 进行快排,时间复杂度是o(n + n*logn)
  • 看了双指针解法,我的理解类似于归并中合并两个有序数组,由于数组两边的元素的值的平方的值是最大的(有负数时),由两边向中间值是递减的。因此可以使用双指针i j,用i指向最左边的元素,j指向最右边的元素,i右移,j左移。开辟一个和旧数组大小一样新数组,k指向新数组的最右边即最大的元素位置。旧i j元素比较平方大小,大的加入新数组,然后移动。循环边界条件是i <= j。注意要加上等号,否则会漏掉一个元素。
  • 收获:对双指针有了一定的理解,1 h。
/**
 * 2023/12/28 第二天 T2
 * 209.长度最小的子数组
 */
//暴力 o(n^2) 超时!!!
    public int minSubArrayLen(int target, int[] nums) {
        int minL = nums.length + 1,sum,l;

        for (int i = 0; i < nums.length; i++) {
            sum = 0;
            l = 0;
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];
                l++;
                if (sum >= target){//满足条件 更新最小值 跳出该层循环
                    if (l < minL) minL = l;
                    break;
                }
            }
        }
        if (minL == nums.length + 1) return 0;
        return minL;
    }

    //滑动窗口 o(n)
    public int minSubArrayLen2(int target, int[] nums) {
        int i = 0, j = 0,sum = 0,minL = nums.length + 1,l = 0;
        //i j 是起始和终止指针,sum是窗口内元素和保证要大于target的最小数组和
        for (j = 0; j < nums.length; j++){
            sum += nums[j];
            while (sum >= target){
                l = j - i + 1;//窗口长度
                minL = Math.min(minL,l);
                sum -= nums[i++];//精髓 i右移 sum的值减去i位置的值,滑动窗口缩小。
            }
        }
        return minL == nums.length + 1 ? 0 : minL;
    }
  • 第一想法是两层for暴力。

  • 滑动窗口的思路(3个要点):

    1.保持窗口内数值总和大于或者等于target,且长度是由i起始位置开始的最小的连续子数组。

    2.移动窗口起始位置如何移动?当前窗口的值大于target,窗口就向前移动,i右移动,也就是窗口缩小了。

    3.移动窗口的终止位置如何移动?窗口的结束位置就是最外层for循环遍历数组的j指针。

  • 收获:对滑动窗口有了初步的理解,1.5 h。

/**
 * 2023/12/28 第二天 T3
 * 59.螺旋矩阵II
 */
public int[][] generateMatrix(int n) {
        int[][] nums = new int[n][n];
        int startX = 0,startY = 0,offset = 1,count = 1,loop = n / 2;
        int i,j;
        while (loop-- > 0){
            i = startX;
            j = startY;
            for(j = startY; j < startY + n - offset; j++){
                nums[i][j] = count++;
            }
            for (i = startX; i < startX + n -offset; i++){
                nums[i][j] = count++;
            }
            for (; j > startY; j--){
                nums[i][j] = count++;
            }
            for (; i > startX; i--){
                nums[i][j] = count++;
            }
            startX++;
            startY++;
            offset += 2; // 边长少2
        }
        if (n % 2 != 0) nums[startX][startY] = count;
        return nums;
    }
  • 没有思路。。

  • 模拟解法思路:

    首先确定循环不变量,即每次循环就是四个边,每个边的的遍历赋值都采用左闭右开的方式。

    其次确定循环的起点坐标为(startX,startY)。确定边长的遍历边界,如第一条边 j < startY + n - offset。我的理解是startY + n - offset就是就是该边的最后一个元素的下标,而我们需要满足的是左闭右开,因此该下标就不能遍历,也就是 j < startY + n - offset。其中最后一个元素的下标等于 起始下标(startY)+边长长度(n - offset)。offset每循环一次会增加2,相当于边长减少2。

  • 收获:模拟算法有了初步的理解,2 h。

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值