代码随想录算法训练营第二天 | 209.长度最小的子数组、59.螺旋矩阵II、区间和、开发商购买土地

209.长度最小的子数组

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili《代码随想录》视频讲解开讲啦!快来打卡!, 视频播放量 163712、弹幕量 850、点赞数 4123、投硬币枚数 3264、收藏人数 1189、转发人数 240, 视频作者 代码随想录, 作者简介 哈工大师兄,在腾讯、百度搬过砖,代码随想录网站:programmercarl.com,相关视频:五分钟看懂【滑动窗口协议】,tcpip协议第15讲:tcp滑动窗口、拥塞窗口以及拥塞控制原理介绍,力扣209 长度最小的子数组,3.17.滑动窗口基本原理,【labuladong】滑动窗口算法核心模板框架,【小白学算法】239. 滑动窗口最大值,【LeetCode 每日一题】3. 无重复字符的最长子串 | 手写图解版思路 + 代码讲解,【5分钟背八股】257:什么是滑动时间窗口算法?——2023马士兵面试突击班,面试阿里,被问:说说什么是滑动窗口算法??答完直接给了30k,E11【模板】单调队列 滑动窗口最值——信息学竞赛算法icon-default.png?t=O83Ahttps://www.bilibili.com/video/BV1tZ4y1q7XE

第一想法:看完题目,很容易就想到暴力法,但看了下数组的长度是10^5,就觉得暴力法性能太低了,应该会超时,想有没有其他更好的方法,基于前两次作业都用到了双指针法,我就用双指针法的思路来想是否能够解决,结果真能解决。
思路:双指针法在这里也可以说说滑动窗口法,用两个指针left和right来表示窗口的区间[left,right],用一个int类型的total变量来记录窗口里的元素之和,count变量来记录窗口中元素的数量。该方法只需用right遍历一次数组,当total>=target时,进入while(total>=target)循环,在循环中不断往右移动left指针,并更新count的值。
方法一:暴力法
两层for循环,第一层i表示窗口起始位置,第二层表示窗口末尾位置
//时间复杂度:O(n^2)
//空间复杂度:O(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)
//空间复杂度:O(1)
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int len = nums.length, total = 0, count = Integer.MAX_VALUE;
        int left = 0, right = 0;
        //滑动窗口
        for (right = 0; right < len; right++) {
            total += nums[right];
            while (total >= target) {
                count = Math.min(count, right - left + 1);
                total -= nums[left];
                left++;
            }
        }
        return count == Integer.MAX_VALUE ? 0 : count;
}
}

59.螺旋矩阵II

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili《代码随想录》算法公开课开讲啦!快来打卡!代码随想录刷题网站:programmercarl.com, 视频播放量 141012、弹幕量 857、点赞数 3115、投硬币枚数 2337、收藏人数 787、转发人数 211, 视频作者 代码随想录, 作者简介 哈工大师兄,在腾讯、百度搬过砖,代码随想录网站:programmercarl.com,相关视频:不喜欢写代码怎么办???还有救么?,【LeetCode 每日一题】54. 螺旋矩阵 | 手写图解版思路 + 代码讲解,力扣算法题刷着吃力真的不是因为你比别人笨,【逆袭】从双非本到阿里算法工程师,从156斤到96斤,聊聊我逆袭的这十年,当你过度准备了一场代码面试时……,听说C++ primer 太厚了 看不进去?,两分钟搞懂滑动窗口算法,致敬3b1b,优先级队列正式登场!大顶堆、小顶堆该怎么用?| LeetCode:347.前 K 个高频元素,这就是传说中的N皇后? 回溯算法安排!| LeetCode:51.N皇后,动态规划再显神通,LeetCode:516.最长回文子序列icon-default.png?t=O83Ahttps://www.bilibili.com/video/BV1SL4y1N7mV/

第一想法:之前做过类似的题,关键要捋清楚根据顺时针方向填入一行或一列元素后,后面要填入的空间边界的变化。

思路:

以四个方向填入元素步骤为一次循环,要循环n/2次。在上边界填入元素时,需要知道左边界,和右边界;在右边界填入数据时,需要知道上和下边界。其他方向填入元素可由图看出。

因此,我们定义四个变量分别来代表四个边界,当某个边界填完元素后,该边界会发生变化。

如果是上边界添加完了。上边界会+1,相反,如果是下边界添加完了,下边界会-1。左右边界同理得出

//时间复杂度O(n^2)
//空间复杂度O(1)
class Solution {
    public int[][] generateMatrix(int n) {
        int left = 0, right = n - 1, upper = 0, under = n - 1;
        int num = 1;
        int[][] matrix = new int[n][n];
        while (upper <= under) {
            //上,往右
            for (int i = left; i <= right; i++) {
                matrix[upper][i] = num++;
            }
            upper++;
            //右,往下
            for (int i=upper;i<=under;i++){
                matrix[i][right]=num++;
            }
            right--;
            //下,往左
            for (int i=right;i>=left;i--){
                matrix[under][i]=num++;
            }
            under--;
            //左,往上
            for (int i=under;i>=upper;i--){
                matrix[i][left]=num++;
            }
            left++;
        }
        return matrix;
    }
}

区间和

 思路:求一个数组下标start到下标end之间的所有元素之和,如果所求区间很多,并且区间很长,则性能很差,会导致超时。采用区间和解法,再往数组添加元素的同时,用一个数组来存储求和的值,num[i]的值表示为0到i区间所有元素的和。由此可得,当求start到end区间的元素和时,直接由num[end]-num[start-1]可得出。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] array = new int[n];
        for (int i = 0; i < n; i++) {
            int number = input.nextInt();
            if (i==0){
                array[i]=number;
                continue;
            }
            array[i]=array[i-1]+number;
        }
        while (input.hasNextInt()){
            int start = input.nextInt();
            int end = input.nextInt();
            if (start==0){
                System.out.println(array[end]);
                continue;
            }
            System.out.println(array[end]-array[start-1]);
        }
    }
}

 开发商购买土地

题目链接:44. 开发商购买土地(第五期模拟笔试)

文章讲解:44. 开发商购买土地 | 代码随想录

思路:在输入元素的过程中计算出每行和每列的元素和,并用数组存储起来,然后分别循环两个数组,经比较可得出最小差。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int m = input.nextInt();
        int total = 0, result = Integer.MAX_VALUE;
        int[] row = new int[n];
        int[] col = new int[m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int number = input.nextInt();
                row[i] += number;
                col[j] += number;
                total += number;
            }
        }
        //横向分
        int rowTotal = 0;
        for (int i = 0; i < n-1; i++) {
            rowTotal += row[i];
            result = Math.min(result, Math.abs(total - 2 * rowTotal));
        }
        //纵向
        int colTotal=0;
        for (int i = 0; i < m-1; i++) {
            colTotal += col[i];
            result = Math.min(result, Math.abs(total - 2 * colTotal));
        }
        System.out.println(result);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值