代码随想录算法训练营 Day2

文章介绍了使用双指针和滑动窗口法解决编程问题的实例,包括有序数组平方、长度最小子数组和螺旋矩阵II。通过这些技巧,展示了数组操作在IT技术中的应用和优化策略。


Day2

一、977.有序数组的平方

  1. 题目链接
  2. 文章讲解
  3. 视频讲解

1. 思路分析

为什么原数组顺序被打破?因为负数平方后会变为正数。

第一想法:比较繁琐。要先找到正负数的中间值,然后双指针依次往两边找,取平方值小的加入新数组。最后哪边未录入,便直接全部平方后加入新数组。步骤像极了归并排序。

优化思路:向新数组填入数据的过程,也不一定非要从左向右。实际上,可以从右向左,从大到小。而现有元素平方的最大值,不是在头,便是在尾。如此,我们无需费力找到正负数的分界线,更无需多确立那么多边界条件。

2. 解法分析

  • 开辟一个新数组,索引指向尾部。
  • 两个指针指向旧数组,一头一尾,比较二者平方后的大小。
  • 索引指针的值 = 平方后较大的值。同时平方后数值较大的指针向中间进一位。
  • 循环的的终止条件利用了索引指针。当新数组全部填充完毕时终止循环。

3. 代码展示

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0, right = nums.length - 1;
        int[] nums2 = new int[nums.length];
        for (int index = nums.length - 1; index >= 0; index--) {
            if (nums[left] * nums[left] >= nums[right] * nums[right]) {
                nums2[index] = nums[left] * nums[left];
                left++;
            }
            else{
                nums2[index] = nums[right] * nums[right];
                right--;
            }
        }
        return nums2;
    }
}

二、209.长度最小的子数组

  1. 题目链接
  2. 文章讲解
  3. 视频讲解

1. 思路分析(滑动窗口法)

这真的是一个非常巧妙的解题思路。

暴力解法:无需多言,两个for循环,n平方的时间复杂度,因时长过长,无法在LeetCode上提交。

滑动窗口法:所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果在这里插入图片描述

通过不断调整框中的内容,右指针右移来补充元素,左指针右移来删除元素。在框中元素和大于等于目标值时统计当前窗口长度。

2. 解法分析

实现该方法要明确以下问题?

  • 窗口里是什么?
  • 什么时候移动窗口结束位置?
  • 什么时候移动窗口起始位置?
  1. 窗口中的便是连续子数组。而我们要找的,就是长度最小、且满足元素和大于等于目标值的窗口。
  2. 移动窗口结束位置:只要窗口数据和小于目标值,就向后移动扩大窗口,直至数据和大于等于。
  3. 移动窗口起始位置:窗口数据和大于等于目标值时,我们便需要缩减窗口来寻求最小的长度。每次检定“窗口数据和大于等于目标值”成功,便与当前最小长度比较一次,同时缩减一次窗口。

3. 注意事项

  • 同在每个起点都遍历一遍的暴力解法相比,滑动窗口法动态地通过终点去找起点,避免了很多无效运算,达成O(n)的时间复杂度。
  • 方法精髓:将数组的遍历索引当做窗口的结束位置,以其为参考动态地调节窗口起始位置

4. 代码展示

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

三、59.螺旋矩阵II

  1. 题目链接
  2. 文章讲解
  3. 视频讲解

1. 思路分析

本题不涉及什么算法。但是对矩阵的模拟过程,讲求对区间精准而又规律的划分、对边界条件的头脑清晰。
找到一般规律,以避免过多的边界条件。

按顺时针顺序螺旋排列元素,使其构成一正方形矩阵。

那么按照元素从小到大的顺序,对这个矩阵中的一圈的填充就应该是:从左到右、从上到下、从右到左、从下到上。

那么如何找到合适的区间呢?左闭右开我比较习惯。关键是要确保每一条线的填充都是按照相同的规则进行。

2. 解法分析

  • 确定每一条线的的位置所在:固定在哪行或哪列?填充顺序如何?区间是多少?
  • 从外向内画圈时,内圈相比外圈起始位置 + 1,终止位置 - 1。
  • 当起始位置等于终止位置时,边界条件的填充。

3. 代码展示

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] matrix = new int[n][n];
        int count = 1, start = 0, end = n - 1;
        while (start < end) {
            for (int i = start; i <end; i++) {
                matrix[start][i] = count++;
            }
            for (int i = start; i < end; i++) {
                matrix[i][end] = count++;
            }
            for (int i = end; i > start; i--) {
                matrix[end][i] = count++;
            }
            for (int i = end; i > start; i--) {
                matrix[i][start] = count++;
            }
            start++;
            end--;
        }
        if (start == end) {
                matrix[start][start] = count;
        }
        return matrix;
    }
}

四、总结

至此,数组的大致方法就过了一遍。

回望去,大抵是通过双指针来操作:头尾指针、快慢指针、滑动窗口。这些巧妙的算法使我意识到,即使是最基础的数据结构也不容小觑。

深夜写博客竟然能够得到莫名的平静与安心。比起躺在床上会想要虚无地看手机,这样更令我觉得安心。
当然最好还是不要搞这么晚了,尽量早早休息。
祝我自己学习愉快~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值