贪心算法应用

news2024/7/6 20:03:28

1. 算法思想

贪心算法一般分为如下四步:

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

选择每一阶段的局部最优,从而达到全局最优

2. 最大自序和

题目描述

题目链接

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

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

示例 1:

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

代码

//贪心
class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        //记录和
        int sum = Integer.MIN_VALUE;
        int count = 0;

        for(int i = 0;i < n;i++){
            count += nums[i];
            sum = Math.max(sum,count); // 取区间累计的最大值(相当于不断确定最大子序终止位置)
            //如果元素为负数,直接重置
            if(count < 0) count = 0; 
        }

        return sum;
    }
}

//DP
class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        //定义dp数组
        int[] dp = new int[n];
        dp[0] = nums[0];
        int ans = dp[0];

        for(int i = 1;i < n;i++){
            dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
            ans = Math.max(ans, dp[i]);
        }

        return ans;
    }
}

3. 跳跃游戏

题目描述

题目链接

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 13 步到达最后一个下标。

代码

class Solution {
    public boolean canJump(int[] nums) {
        if (nums.length == 1) {
            return true;
        }
        //覆盖范围, 初始覆盖范围应该是0,因为下面的迭代是从下标0开始的
        int coverRange = 0;
        //在覆盖范围内更新最大的覆盖范围
        for (int i = 0; i <= coverRange; i++) {
            coverRange = Math.max(coverRange, i + nums[i]);
            if (coverRange >= nums.length - 1) {
                return true;
            }
        }
        return false;
    }
}

4. 加油站

题目描述

题目链接

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gascost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

示例 1:

输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3
解释:3 号加油站(索引为 3)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。

代码

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
      int n = gas.length;
      //当前剩余油量
      int curSum = 0;
      //总的剩余油量
      int tolSum = 0;
      //起点
      int startIndex = 0;
      for(int i = 0;i < n;i++){
          curSum += gas[i] - cost[i];
          tolSum += gas[i] - cost[i];
          if(curSum < 0){
              startIndex = (i + 1) % n;
              curSum = 0;
          }
      }
      //总剩余油量小于0,肯定没有起始点
      if(tolSum < 0) return -1;
      return startIndex;
    }
}

5. 分发糖果

题目描述

力扣链接

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 212 颗糖果。

代码

class Solution {
    public int candy(int[] ratings) {

         /**
         分两个阶段
         1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1
         2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大
    */
        int n = ratings.length;
        int[] candies = new int[n];
        candies[0] = 1;

        //从前往后
        for(int i = 1;i < n;i++){
             candies[i] = (ratings[i] > ratings[i - 1]) ? candies[i - 1] + 1 : 1;
        }

        //从后往前
        for(int i = n - 2;i >= 0;i--){
             if (ratings[i] > ratings[i + 1]) {
                candies[i] = Math.max(candies[i], candies[i + 1] + 1);
            }
        }

        int sum = 0;
        //计算
        for(int num : candies){
            sum += num;
        }

        return sum;
    }
}

根据身高重建队列

题目描述

题目链接

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

示例 1:

输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 01 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0123 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。

代码

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        // 身高从大到小排(身高相同k小的站前面)
        Arrays.sort(people, (a, b) -> {
            if (a[0] == b[0]) return a[1] - b[1];
            return b[0] - a[0];
        });
        LinkedList<int[]> que = new LinkedList<>();

        for (int[] p : people) {
            //表示在链表指定位置插入元素
            // [[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]
            //[7,0]:表示在索引为0处插入[7,0](索引相同,前插)
            que.add(p[1],p);
        }

        return que.toArray(new int[people.length][]);
    }
}

注意

  • 分发糖果盒根据升高重建队列,这两个题目都是有两个维度,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度

6. 无重叠区间

题目描述

题目链接

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠

示例 1:

输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

代码

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {

        //按照左边界排序
        Arrays.sort(intervals, (a, b) -> Integer.compare(a[0],b[0]));

        int count = 0;
        int n = intervals.length;
        for(int i = 1;i < n;i++){
            //判断两个区间是否有重叠
            if(intervals[i - 1][1] > intervals[i][0]){
                count++;
                //记录最小右边界
                intervals[i][1] = Math.min(intervals[i][1], intervals[i - 1][1]);
            }
        }

        return count;

    }
}

相似题目

用最少数量的箭引爆气球

7. 划分字母区间

题目描述

力扣链接

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

示例:

输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。

提示:

  • S的长度在[1, 500]之间。
  • S只包含小写字母 'a''z'

思路

可以分为如下两步:

  • 统计每一个字符最后出现的位置
  • 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点

代码

class Solution {
public:
    vector<int> partitionLabels(string S) {
        int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置
        for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
            hash[S[i] - 'a'] = i;
        }
        vector<int> result;
        int left = 0;
        int right = 0;
        for (int i = 0; i < S.size(); i++) {
            right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界
            if (i == right) {
                result.push_back(right - left + 1);
                left = i + 1;
            }
        }
        return result;
    }
};


8. 合并区间

题目描述

力扣链接

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3][2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4][4,5] 可被视为重叠区间。

提示:

  • 1 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 104

代码

class Solution {
    public int[][] merge(int[][] intervals) {
        int n = intervals.length;
        if(n == 1) return intervals;
        //按照左边界排序
        Arrays.sort(intervals,(a,b)->Integer.compare(a[0],b[0]));
        //存储返回数组
        int[][] res = new int[n][2];
        //定义数据的大小
        int size = 0;
        int i = 1;
        for(;i < n;i++){
            //比较两个元素的右边界和左边界
            if(intervals[i-1][1] < intervals[i][0]){
                res[size][0] = intervals[i-1][0];
                res[size][1] = intervals[i-1][1];
                size++;     
            }else{//更新左边界和右边界
                intervals[i][0] = intervals[i-1][0];
                intervals[i][1] = Math.max(intervals[i-1][1], intervals[i][1]);
            }
        }
        //处理最后一个元素  
        res[size][0] = intervals[i - 1][0];
        res[size][1] = intervals[i - 1][1];
        size++; 
        return Arrays.copyOf(res,size);
    }
}

9. 单调递增的数字

题目描述

力扣链接

当且仅当每个相邻位数上的数字 xy 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增

示例 1:

输入: n = 10
输出: 9

示例 2:

输入: n = 1234
输出: 1234

示例 3:

输入: n = 332
输出: 299

提示:

  • 0 <= n <= 109

思路

  • 本题只要想清楚个例,例如98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]减一,strNum[i]赋值9,这样这个整数就是89

代码

class Solution {
    public int monotoneIncreasingDigits(int n) {
       /**
            98 -> 89
        */

        String s = String.valueOf(n);
        char[] chars = s.toCharArray();
        int len = chars.length;
        int start = len;
        // 98
        for(int i = len - 2;i >= 0;i--){
            if (chars[i] > chars[i + 1]) {
                chars[i]--; // 9 - > 8
                start = i + 1; // 记录该位置,8 - > 9
            }
        }
        for (int i = start; i < len; i++) {
            chars[i] = '9';
        }

        return Integer.parseInt(String.valueOf(chars));
    }

    
}

参考

代码随想录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25942.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用Servlet 编写hello world

第一次接触 Servlet&#xff0c;使用 Servlet 编写代码并配合 Tomcat 在浏览器中展示代码效果&#xff0c;也算是自己这么长时间学习java的一次飞升吧。 本文总结了六步使用 Servlet 编写 helloworld步骤&#xff0c;希望给初学Servlet的同学一些帮助。 0、准备工作 1&#xff…

Python 随机函数random详解

介绍这7个随机数的方法应用&#xff1a; 1、random.random&#xff08;&#xff09;查看源码 说明&#xff1a;用于生成一个0到1的随机符点数: 0 < x < 1.0 import random for i in range(10):print(random.random()) 2、random.uniform&#xff08;&#xff09;查看源码…

深度学习(14)—— 关于Tensorboard

深度学习&#xff08;14&#xff09;—— 关于Tensorboard 文章目录深度学习&#xff08;14&#xff09;—— 关于Tensorboard前言1. “一参数一图”2.“多参数一图”3. “一栏一图”4. “一栏多图”在模型训练过程中loss和acc都会发生变化&#xff0c;常常需要记录这些值&…

Spring Security(2)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 前面已经把需要的环境准备好了&#xff0c;包括数据库和SQL语句&#xff0c;现在再来写代码。至于安装MySQL什么的就跳过去了&#xff0c;娘度子里面一大把。 先…

保护Excel表格的4种常用方法

今天来说说&#xff0c;根据不同需求&#xff0c;我们可以给Excel表格设置保护的4种常用方法&#xff0c;记得保存收藏&#xff0c;总有一个适合你。 方法一&#xff1a; 如果不想Excel表格被他人随意打开&#xff0c;可以设置“打开密码”&#xff0c;这样只有输入设置的密码…

OpenSergo 流量路由:从场景到标准化的探索

流量路由&#xff0c;顾名思义就是将具有某些属性特征的流量&#xff0c;路由到指定的目标。流量路由是流量治理中重要的一环&#xff0c;多个路由如同流水线一样&#xff0c;形成一条路由链&#xff0c;从所有的地址表中筛选出最终目的地址集合&#xff0c;再通过负载均衡策略…

git ssh permission denied解决办法

git ssh permission denied解决办法 1. SSH配置 参考链接 SSH配置文档 2. ssh报错(permission denied) 解决方式&#xff1a; 找到git安装目录 进入etc/ssh文件夹内&#xff0c;找到ssh_config文件&#xff0c;在# Added by git-extra后面添加t替换代码具体参考下面图片 H…

2022强网拟态pwn-store

2022强网拟态pwn-store 这是一个综合题&#xff0c;io链接的构造&#xff0c;orw的系统位数的限制 首先是这个沙箱&#xff0c;64位只有r和w&#xff0c;一开始看的时候很纳闷多了32位的限制&#xff0c;64位还没有o&#xff0c;查了一下才知道这样的seccomp-tools是以64位的…

Design Compiler工具学习笔记(4)

目录 引言 知识储备 实际操作 设计源码 Vivado2018.3仿真 VCS2016仿真 Tcl脚本 约束脚本 MY_TOP.tcl 运行脚本 RUN.tcl 引言 本篇继续学习 DC的基本使用。本篇主要学习 DC 需要的环境约束。 前文链接&#xff1a; Design Compiler工具学习笔记&#xff08;1&#x…

【苹果推iMessage位置推相册共享推送】软件安装上传到appstore都是需要的Activity

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

maxcompute优化慢执行语句思路

maxcompute慢执行任务优化如何锁定慢执行任务&#xff1f;判断是何种类型的慢任务如何锁定慢执行任务&#xff1f; 第一步&#xff1a;如果是周期任务可以通过任务执行日志中的LogView 链接查看 &#xff0c;如果是临时任务则通过maxcompute命令行 执行wait instanceId instanc…

现代密码学导论-2-古典密码及其密码分析

目录 1.3 古典密码和密码分析 1.3.1 凯撒密码 Caesar’s cipher 1.3.2 移位密码 shift cipher 1.3.3 充分密钥空间原则 1.3.4 单表代换密码 mono-alphabetic substitution cipher 1.3.5 利用字母频率对移位密码的一种改进攻击 1.3.6 维吉尼亚密码(多表代换密码)Vigenere…

Ansys Zemax | 使用 OpticStudio 进行闪光激光雷达系统建模(上)

前言 在消费类电子产品领域&#xff0c;工程师可利用激光雷达实现众多功能&#xff0c;如面部识别和3D映射等。尽管激光雷达系统的应用非常广泛而且截然不同&#xff0c;但是 “闪光激光雷达” 解决方案通常都适用于在使用固态光学元件的目标场景中生成可检测的点阵列。凭借具…

教育行业数据可视化应用方案与实践

教育行业背景介绍 随着信息技术发展&#xff0c;教育领域中的学习方式、教学模式、教学内容均已发生重大变革&#xff0c;以云计算、人工智能、物联网、大数据等技术的结合&#xff0c;“智慧教育”的需求也变的紧迫&#xff0c;需要围绕“智慧教育”而产生的产品和解决方案也…

课程思政案例----简道云零代码应用开发实训平台

为了更好推动零代码开发课程的思政建设&#xff0c;在传递大数据相关知识和技能的同时帮助学生塑造正确的世界观、人生观和价值观。我们整理了与简道云平台结合的应用案例&#xff0c;开放给全国各大高校使用。 1、杨卫红&#xff1a;一位55岁不懂代码的农经员&#xff0c;为家…

Windows下将文件夹映射为磁盘

Windows下将文件夹映射为磁盘背景描述方法一&#xff1a;使用命令方法二&#xff1a;映射网络驱动器背景描述 公司发的新电脑&#xff0c;只有普通用户权限&#xff0c;所以可想而知磁盘只有一个C盘&#xff0c;但是以前习惯性的将一些软件啥的放在D盘中&#xff0c;所以把C盘…

打好“三场仗”,数据库新晋厂商石原子胜券在握

纵观数字经济时代&#xff0c;数据规模呈爆发式增长&#xff0c;国产化替代加速发展。据中国信通院《数据库发展研究报告(2021年)》预测&#xff0c;预计到2025年&#xff0c;全球数据库市场规模将达到798亿美元&#xff0c;其中&#xff0c;中国数据库市场总规模将达到688亿元…

js文件模块化引用问题(JavaScript modules)

有个前端项目&#xff0c;需要用到配置文件。这个配置文件实在是太大了&#xff0c;就想拆成多个小的&#xff0c;然后一一引入&#xff0c;组合成一个完整的配置文件。 如果是vue代码&#xff0c;这种情况根本是手到擒来&#xff0c;不费吹灰之力&#xff0c;而该前端项目是个…

(WRF-UCM)高精度城市化气象动力模拟技术

气候变化及应对是政府、科学界及商业界关注的焦点。气候是多个领域&#xff08;生态、水资源、风资源及碳中和等问题&#xff09;的主要驱动因素&#xff0c;合理认知气候变化有利于解释生态环境变化机理及过程&#xff0c;而了解现在、未来气候变化则是进行生态、环境及能源评…

vs2022 编译遇见编译器堆空间不足,解决办法(针对CMAKE工程)

1、原因&#xff1a; 就是编译工程文件太大&#xff0c;导致堆栈溢出。原始vs默认的编译器是32位&#xff0c;我们设置为64位就可解决部分问题。 具体可能造成的原因可以参考&#xff1a; 错误 C1060 |微软学习 (microsoft.com) 2、解决&#xff1a; 1、需要提前安装cmake…