• 第二课 前缀和、差分、双指针扫描


    第二课 前缀和、差分、双指针扫描

    lc1.两数之和–简单

    题目描述

    给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

    你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

    你可以按任意顺序返回答案。

    示例 1:

    输入:nums = [2,7,11,15], target = 9
    输出:[0,1]
    解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
    
    • 1
    • 2
    • 3

    示例 2:

    输入:nums = [3,2,4], target = 6
    输出:[1,2]
    
    • 1
    • 2

    示例 3:

    输入:nums = [3,3], target = 6
    输出:[0,1]
    
    • 1
    • 2

    提示:

    • 2 <= nums.length <= 104
    • -109 <= nums[i] <= 109
    • -109 <= target <= 109
    • 只会存在一个有效答案

    代码展示

    class Solution {
    public:
        vector<int> twoSum(vector<int>& numbers, int target) {
            // pair
            vector<pair<int,int>> nums;
            for (int i = 0; i < numbers.size(); i++) {
                nums.push_back(make_pair(numbers[i], i));
            }
            sort(nums.begin(),nums.end());
            int j = nums.size() - 1;
            for (int i = 0; i < nums.size(); i++) {
                while (i < j && nums[i].first + nums[j].first > target) j--;
                if (i < j && nums[i].first + nums[j].first == target) {
                    return {nums[i].second, nums[j].second};
                }
            }
            return {};
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    lc11.盛最多水的容器–中等

    题目描述

    给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

    找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

    返回容器可以储存的最大水量。

    **说明:**你不能倾斜容器。

    示例 1:

    img

    输入:[1,8,6,2,5,4,8,3,7]
    输出:49 
    解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
    
    • 1
    • 2
    • 3

    示例 2:

    输入:height = [1,1]
    输出:1
    
    • 1
    • 2

    提示:

    • n == height.length
    • 2 <= n <= 105
    • 0 <= height[i] <= 104

    代码展示

    class Solution {
    public:
        int maxArea(vector<int>& height) { 
    /*
    i
            int i = 0, j = height.size() - 1;
            int ans = 0;
            while (i < j) {
                ans = max(ans, min(height[i], height[j]) * (j - i));
                if (height[i] == height[j]) i++, j--;
                else if (height[i] < height[j]) i++; else j--; 
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    lc15.三数之和–中等

    题目描述

    给你一个整数数组 nums判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

    你返回所有和为 0 且不重复的三元组。

    **注意:**答案中不可以包含重复的三元组

    示例 1:

    输入:nums = [-1,0,1,2,-1,-4]
    输出:[[-1,-1,2],[-1,0,1]]
    解释:
    nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
    nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
    nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
    不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
    注意,输出的顺序和三元组的顺序并不重要。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例 2:

    输入:nums = [0,1,1]
    输出:[]
    解释:唯一可能的三元组和不为 0 。
    
    • 1
    • 2
    • 3

    示例 3:

    输入:nums = [0,0,0]
    输出:[[0,0,0]]
    解释:唯一可能的三元组和为 0 。
    
    • 1
    • 2
    • 3

    提示:

    • 3 <= nums.length <= 3000
    • -105 <= nums[i] <= 105

    代码展示

    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            sort(nums.begin(), nums.end());
            // nums[i] + nums[j] + nums[k] = 0
            // nums[j] + nums[k] = -nums[i]
            // i < j < k
            vector<vector<int>> ans;
            for (int i = 0; i < nums.size(); i++) {
                if (i > 0 && nums[i] == nums[i - 1]) continue;
                auto all_two_sums = twoSum(nums, i + 1, -nums[i]);
                for (auto jk : all_two_sums) {
                    ans.push_back({nums[i], jk[0], jk[1]});
                }
            }
            return ans;
        }
    
    private:
        vector<vector<int>> twoSum(vector<int>& numbers, int start, int target) {
            vector<vector<int>> ans;
            int j = numbers.size() - 1;
            for (int i = start; i < numbers.size(); i++) {
                if (i > start && numbers[i] == numbers[i - 1]) continue;
                while (i < j && numbers[i] + numbers[j] > target) j--;
                if (i < j && numbers[i] + numbers[j] == target) {
                    ans.push_back({numbers[i], numbers[j]});
                }
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    lc42.接雨水–困难

    题目描述

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

    示例 1:

    img

    输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
    输出:6
    解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 
    
    • 1
    • 2
    • 3

    示例 2:

    输入:height = [4,2,0,3,2,5]
    输出:9
    
    • 1
    • 2

    提示:

    • n == height.length
    • 1 <= n <= 2 * 104
    • 0 <= height[i] <= 105

    代码展示

    class Solution {
    public:    //单调栈的做法
        int trap(vector<int>& height) {
            int ans = 0;
            stack<Rect> s;
            s.push({0, 0});
            for (int h : height) {
                int w = 0;
                while (s.size() > 1 && s.top().height <= h) {
                    w += s.top().width;
                    int bottom = s.top().height;
                    s.pop();
                    ans += w * max(0, min(s.top().height, h) - bottom);
                }
                s.push({h, w + 1});
            }
            return ans;
        }
    
    private:
        struct Rect {
            int height;
            int width;
        };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    class Solution {
    public:    //前后缀最大值的做法
        int trap(vector<int>& height) {
            int n = height.size();
            pre[0] = suf[n + 1] = 0;
            for (int i = 1; i <= n; i++) pre[i] = max(pre[i - 1], height[i - 1]);
            for (int i = n; i; i--) suf[i] = max(suf[i + 1], height[i - 1]);
            int ans = 0;
            for (int i = 1; i <= n; i++) {
                ans += max(0, min(pre[i - 1], suf[i + 1]) - height[i - 1]);
            }
            return ans;
        }
    
    private:
        int pre[100005];
        int suf[100005];
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    lc53.最大子数组和–中等

    题目描述

    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    子数组 是数组中的一个连续部分。

    示例 1:

    输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
    输出:6
    解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
    
    • 1
    • 2
    • 3

    示例 2:

    输入:nums = [1]
    输出:1
    
    • 1
    • 2

    示例 3:

    输入:nums = [5,4,-1,7,8]
    输出:23
    
    • 1
    • 2

    提示:

    • 1 <= nums.length <= 105
    • -104 <= nums[i] <= 104

    代码展示

    class Solution {
    public:    //前缀和的做法
        int maxSubArray(vector<int>& nums) {
            // nums: 0~n-1
            // sum: 0,1~n
            int n = nums.size();
            vector<long long> sum(n + 1, 0);
            for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];
            vector<long long> pre(n + 1, 0);
            // 前缀最小值(前i个数的最小值)
            pre[0] = sum[0];
            for (int i = 1; i <= n; i++) pre[i] = min(pre[i - 1], sum[i]);
    
            long long ans = -1e10;
            // long long prefix_min = sum[0];
            // int_max = 2147483647 = 2^31-1 = 2e9
            for (int i = 1; i <= n; i++) {
                // i之前的j --> j<=i-1
                ans = max(ans, sum[i] - pre[i-1]);
                // prefix_min = min(prefix_min, sum[i]);
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    class Solution {
    public:    //贪心的做法
        int maxSubArray(vector<int>& nums) {
            int sum = 0;
            int ans = -2e9;
            for (int i = 0; i < nums.size(); i++) {
                sum += nums[i];
                ans = max(ans, sum);
                if (sum < 0) sum = 0;
            }
            return ans;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    c语言强制类型转换
    Redis的介绍以及底层原理剖析
    模拟ASP.NET Core MVC设计与实现
    300.最长递增子序列 | 354.俄罗斯套娃信封问题
    Java自定义ClassLoader加载外部类
    nodejs学习week01
    [附源码]java毕业设计乒乓球俱乐部管理系统
    【单元测试】java中assert(断言)的使用
    基于STM32设计的智能家庭防盗系统(华为云IOT)(224)
    【zabbix监控四】zabbix之监控tomcat服务报警
  • 原文地址:https://blog.csdn.net/BH04250909/article/details/133610644