代码随想录Day1.5—leetcode.209 && leetcode.59

leetcode.209 长度最小的子数组 

209. 长度最小的子数组 

题目描述:

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

进阶:

  • 如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

暴力解法

思路:题目要求找出数组中其总和大于等于 target 的长度最小的 连续子数组用两层for循环实现

直接创建一个int类型的变量sum,连续的sum+=nums[i],然后删减一些前边或后边的元素,看是否仍然满足条件,以达到连续子数组的数组长度最小。


class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result=Integer.MAX_VALUE; //最终的结果
        int subLength=0; //也即子序列的长度
        for(int i=0;i<nums.length;i++){//i为子序列的起点下标
            int sum=0; //子序列的数值之和
            for(int j=i;j<nums.length;j++){//j为子序列的终点下标
                sum+=nums[j];
                if(sum>=target){
                    subLength=j-i+1;
                    result=result<subLength?result:subLength; //不断比较,找符合条件最短的子序列
                    break;
                }
            }
        }
        return result==Integer.MAX_VALUE?0:result;
    }
}

滑动窗口: 将O(n2)暴力解法降为O(n)

解题思路:题目需要的是大于等于target的连续的子数组,考虑用滑动窗口,不断调节子序列的首位指针使长度最小

在暴力解法中,一个for循环是滑动窗口的起始位置,另一个for循环是滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。

为了避免再次陷入暴力解法的怪圈,使用滑动窗口只有一个for循环时,for循环的索引 就定义为滑动窗口的终点。那么滑动窗口的起点怎么定义并移动?以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,来看一下查找的过程:

209.长度最小的子数组

最后找到 4,3 是最短距离。

其实从动画中可以发现滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。

这里窗口是满足其和>=target的长度最小的连续子数组,窗口的结束位置是for循环的int i,窗口的起点是每次跟着 i 递增而慢慢变大的left。(int left=0不能放在for循环的第一行,要放在其外面)

//双指针法:左右指针围起来的是一个连续子数组,故又称为滑动指针
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result=Integer.MAX_VALUE; //最终的结果,也即子序列的长度
        int sum=0; //子序列的数值之和
        int left=0;  //这个不能放在for循环里边
        for(int i=0;i<nums.length;i++){//i为子序列的下标终点
            sum +=nums[i];
            while(sum>=target){//left为子序列的下标终点
                result=Math.min(result,i-left+1);
                sum -=nums[left++];
            }
        }
        return result==Integer.MAX_VALUE?0:result;
    }
}

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

leetcode.59 螺旋矩阵 

59. 螺旋矩阵

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

解题思路:本题并不涉及到什么算法,就是模拟走一圈的过程,但却十分考察对代码的掌控能力。首要的是定区间(左闭右闭或左闭右开)

//方法一
class Solution {
    //左闭右闭区间,使用四个变量(left, right, top, bottom)来跟踪矩阵的边界
    public int[][] generateMatrix(int n) {
        int[][] matrix=new int[n][n];
        int total=n*n;
        int count=1;
        int left=0,right=n-1,top=0,bottom=n-1;
        while(count<=total){
            for(int i=left;i<=right;i++){
                matrix[top][i]=count++;
            }
            top++;
            for(int i=top;i<=bottom;i++){
                matrix[i][right]=count++;
            }
            right--;
            for(int i=right;i>=left;i--){
                matrix[bottom][i]=count++;
            }
            bottom--;
            for(int i=bottom;i>=top;i--){
                matrix[i][left]=count++;
            }
            left++;
        }
        return matrix;
    }
}
//方法2 坚持每条边左闭右开的原则
class Solution {
    public int[][] generateMatrix(int n) {
        int loop=0;// 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处
        int[][] res=new int[n][n];
        int start=0; //定义每循环一个圈的起始位置
        int count=1;  用来给矩阵中每一个空格填充的数字
        int i, j;  //二维数组元素的下标索引
        while(loop++ < n/2){
            // 下面开始的四个for就是模拟转了一圈
            //模拟上侧从左到右(左闭右开)
            for(j=start;j<n-loop;j++){
                res[start][j]=count++;
            }

            //模拟右侧从上到下(左闭右开)
            for(i=start;i<n-loop;i++){
                res[i][j]=count++;
            }

            //模拟下侧从右到左(左闭右开)
            for(;j>=loop;j--){
                res[i][j]=count++;
            }

            //模拟左侧从下到上(左闭右开)
            for(;i>=loop;i--){
                res[i][j]=count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            start++;
        } 
        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
            if(n%2==1){
                res[start][start]=count; // 矩阵中间的位置,例如:n为3, 中间的位置坐标就是(1,1),n为5,中间位置坐标就是(2, 2)
            }
            return res;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值