羊羊刷题笔记Day02/60 | 第一章 数组P2 | 977. 有序数组的平方、209. 长度最小的子数组、59. 螺旋矩阵II

学习资料:
代码随想录
977.有序数组的平方
209.长度最小的子数组
59.螺旋矩阵II

977 有序数组的平方

动手写

总思路是先平方再排序,排序有很多种方法,但现有记忆只能写效率最低的冒泡排序:

public int[] sortedSquares(int[] nums) {
    // [-3,-1,0,2]
    // 先平方
    for (int i = 0; i < nums.length; i++) {
        nums[i] = nums[i] * nums[i];
    }


    // [9,1,0,4]
    // 后排序 - 冒泡排序
    for (int i = 0; i <= nums.length - 2; i++) {
        for (int i1 = i + 1; i1 <= nums.length - 1; i1++) {
            if (nums[i1] < nums[i]){
                // 交换位置
                int temp = nums[i1];
                nums[i1] = nums[i];
                nums[i] = temp;
            }
        }
    }
    return nums;
}

解答成功:
执行耗时:637 ms,击败了5.02% 的Java用户
内存消耗:44.5 MB,击败了5.11% 的Java用户

看视频

双指针法:
为什么会想到双指针法?
虽然和第一天名字一样,但仅仅是名字一样用了两个指针,原理不同。
结合本题的特点,由于该数组是递增的,且包含了负数,负数有可能平方之后更大
**因此,越往两边的数平方后越大。**那么就设置两个指针在头尾比较,最大的插入新数组。

对比起来,双指针更针对本题的情况,取得了最佳性能。
而传统的方法更为通用,无论数组是否有序都可以使用。
反思:优化算法可以从“是否充分运用题目条件,题目特点”思考

双指针代码:

// 双指针
int k = nums.length - 1;
int[] result = new int[nums.length];

// 注意i和j范围,由于i == j时还要判断并且写入新数组,因此为<=
for (int i = 0, j = nums.length - 1; i <= j; ) {
    if ((nums[i] * nums[i]) > (nums[j] * nums[j])) {
        // 给新数组赋予最大值
        result[k] = nums[i] * nums[i];
        i++;
        k--;
    }
    else {
        // 给新数组赋予最大值
        result[k] = nums[j] * nums[j];
        k--;
        j--;
    }
}
return result;

此时的时间复杂度为O(n)
执行耗时:1 ms,击败了100.00% 的Java用户
内存消耗:43.7 MB,击败了39.33% 的Java用户

209 长度最小的子数组

动手写

想法:使用双指针先选定一个连续大区域,然后左指针往右缩小值最小。以此不断生成最小区域,取最小的数组长度值min。但自己敲的代码由于时间复杂度高,面对大量数组测试时TimeOut

public int minSubArrayLen(int target, int[] nums) {
    // 双指针
    int l = 0;
    int r;
    int min = 0;

    for (r = 0; r < nums.length; r++) {
        // 指针内区域相加 - 获得区域
        int sum = 0;
        for (int i = l; i <= r; i++) {
            sum = sum + nums[i];
        }

        // 优化区域
        if (sum >= target) {
            int num = minification(++l, r, nums, target);
            if (min == 0 || num < min){
                min = num;
            }
            l++;
        }
    }
    return min;

}

public int minification(int l, int r, int[] nums, int target) {
    // 缩小范围
    int sum1 = 0;
    for (int i = l; i <= r; i++) {
        sum1 = sum1 + nums[i];
    }
    if (sum1 >= target) {
        // 如果还是>= 则继续优化
        return minification(++l, r, nums, target);
    } else {
        // 出现<情况时返回l指针
        l--;
        System.out.print(l);
        System.out.print(r);
        return r - l + 1;
    }
}

看视频后

计算sum时候写的太复杂了,借助上层循环完成相加操作,根据视频优化后:

// 双指针
int l = 0;
int r;
int min = Integer.MAX_VALUE;
int sum = 0;

for (r = 0; r < nums.length; r++) {
    // 指针内区域相加 - 获得区域
    sum = sum + nums[r];

    // 优化区域
    while (sum >= target) {
        // 记录当前值
        min = Math.min(min, r - l + 1);
        sum = sum - nums[l];
        l++;
    }

}
return min == Integer.MAX_VALUE? 0 : min;

反思:利用已做的事情,优化不必要的时间复杂度

59 螺旋矩阵 II

本题对昨天的"循环不变量"进行巩固,四次循环如果还不设定一个标准,就乱套了。

卡哥:
大家写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

代码:左闭右开[ )

public int[][] generateMatrix(int n) {
int x = 0;
int y = 0;
int offset = 1;
int count = 1;
int loop = 0;//循环次数
int[][] arr = new int[n][n];

while (loop++ < n / 2) {
    int i = x;
    int j = y;

    // →
    for (; j < n - offset; j++) {
        arr[i][j] = count++;
    }
    // ↓
    for (; i < n - offset; i++) {
        arr[i][j] = count++;
    }
    // ←
    for (; j >= offset; j--) {
        arr[i][j] = count++;
    }
    // ↑
    for(; i >= offset; i--){
        arr[i][j] = count++;
    }

    // 改变参数
    offset++;
    x++;
    y++;
}

// 特殊:当n为奇数时,填补中间数值
if (n % 2 == 1) {
    arr[x][y] = count;
}

return arr;
}

要非常注意四条边的边界划分:
ee846f0c.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值