代码随想录(八):贪心算法

news2024/11/6 9:50:53

文章目录

      • 455.分发饼干
      • 376. 摆动序列
      • 53. 最大子数组和
      • 122. 买卖股票的最佳时机 II
      • 55. 跳跃游戏
      • 1005. K 次取反后最大化的数组和
      • 134. 加油站
      • 860. 柠檬水找零
      • 135. 分发糖果
      • 406. 根据身高重建队列

455.分发饼干

题目链接

C++代码:

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int res = 0;
        for (int i = 0, j = 0; i < g.size(); i++) {
            while (j < s.size() && s[j] < g[i]) j++;
            if (j < s.size()) {
                res++;
                j++;
            }
        }
        return res;
    }
};

376. 摆动序列

题目链接

解题思路
第 1 步:摆动序列的连续数字之间的差需要在正数和负数之间交替,因此首先需要去除连续相同的数
第 2 步:连续数字的收尾值一定在摆动序列中,同时找出数组中的局部最大值和局部最小值放入摆动序列中。请添加图片描述
C++代码:

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        nums.erase(unique(nums.begin(), nums.end()), nums.end());
        int res = 2;
        if (nums.size() <= 2) return nums.size();
        for (int i = 1; i < nums.size() - 1; i++) {
            if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) res++;
            if (nums[i] < nums[i - 1] && nums[i] < nums[i + 1]) res++;
        }
        return res;
    }
};

53. 最大子数组和

题目链接

解题思路

局部最优:当前连续和为负数的时候立刻放弃,从下一个元素重新计算连续和,因为负数加上下一个元素连续和只会越来越小。
全局最优:选取最大连续和
局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。

从代码角度上来讲:
遍历 nums,从头开始用 sum 累积,如果 sum 一旦加上 nums[i] 变为负数,那么就应该从 nums[i+1] 开始从 0 累积 sum 了,因为已经变为负数的 sum,只会拖累总和。

这相当于是暴力解法中的不断调整最大子序和区间的起始位置。

C++代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sum = 0, res = INT_MIN;
        for (int i = 0; i < nums.size(); i++) {
            sum += nums[i];
            if (sum > res) res = sum; // 取区间累计的最大值(相当于不断确定最大子序终止位置)
            if (sum < 0) sum = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
        }
        return res;
    }
};

122. 买卖股票的最佳时机 II

题目链接

解题思路

题意是获得利润的最大值,可把这个问题看作:当天买入股票,后一天卖出。若后一天卖出时出现亏损,则头一天也就不买入。这样在算利润时,只把每天买卖股票收益为正值时,计入最终总利润。

C++代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;
        if (prices.size() == 1) return res;
        for (int i = 1; i < prices.size(); i++) 
            res += max(0, prices[i] - prices[i - 1]);
        return res;
    }
};

55. 跳跃游戏

题目链接

解题思路

题意:数组中的每个元素代表你在该位置可以跳跃的最大长度,判断最终是否能够到达最后一个下标。
使用head来记录能够到达的最远的位置,如果当前位置能够到达的最远位置比head要远,则更新head。通过head可判断最终能否到达最后一个下标。
那么这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点!
每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围head
在这里插入图片描述

C++代码:

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int head = 0;
        if (nums.size() == 1) return true; // 只有一个元素,就是能达到
        for (int i = 0; i <= head; i++) { // 注意这里是小于等于head
            head = max(head, i + nums[i]);
            if (head >= nums.size() - 1) return true; // 说明可以到达到终点了
        }
        return false;
    }
};

1005. K 次取反后最大化的数组和

题目链接

解题思路
题意:对数组中的元素进行k次取反,使得最终数组中的元素和最大。
首先将元素从小到大进行排序,依次让数组中较小的负数变为正数,可使元素和达到最大。
如果将所有的负数都转变为正数了,而k依然大于0,此时判断k是否为奇数,若k为奇数,则从小将数组进行排序,将排序后的最小非负数转变为负值。最后求得数组中元素和即可。

C++代码:

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        int res = 0;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] < 0 && k > 0) { // 依次将较小的负数转变为正数
                nums[i] *= -1;
                k--;
            }
        }
        if (k % 2 == 1) { // 此时将最小的非负数乘上-1
            sort(nums.begin(), nums.end());
            nums[0] *= -1;
        }
        for (auto c: nums) res += c;
        return res;
    }
};

134. 加油站

题目链接

解题思路
由于环路上有 n 个加油站,那么我们可以从 n 个加油站中依次选取第 i 个加油站作为起点进行讨论
如果把第 i 个加油站作为起点,到达第 i + j 个加油站时,发现当前汽车剩余油量cur_gas与第i + j个加油站的汽油总和小于 cost[i + j] 时,也就意味着此时汽车无法到达第i + j + 1个加油站,那么可推出第 i 个加油站到第 i + j 个加油站中任意一个加油站作为起点都无法到达第i + j + 1 个加油站,因此接下来将第i + j + 1个加油站作为起点继续讨论。

C++代码:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int n = gas.size(); // 加油站的个数
        for (int i = 0, j; i < n; ) {
            int cur_gas = 0; // 处于起点的汽车剩余油量为0
            for (j = 0; j < n; j++) { // 从第i个加油站出发,观察汽车能够走到哪个加油站
                int k = (i + j) % n; 
                cur_gas += gas[k]; // 当汽车到达第 k 个加油站时,加上gas[k]的汽油量
                if (cur_gas - cost[k] < 0) break; // 当前汽车的油量无法到达下一个加油站
            }
            if (j == n) return i; // 表明此时汽车可以绕环行驶一周
            i = i + j + 1; // 此时表明第i个加油站到第i+j个加油站作为起点都无法到达第i+j+1个加油站
                           // 因此把第i+j+1个加油站作为起点继续讨论 
        }
        return -1;
    }
};

860. 柠檬水找零

题目链接

解题思路
fiveten两个变量来存储钱包里的5美元和10美元分别有多少张,接着分情况讨论:

  • 如果顾客支付的是5美元,则five++
  • 如果顾客支付的是10美元,则先要判断当前钱包中是否有5美元的纸币,然后在进行找零
  • 如果顾客支付的是20美元,则首先判断当前钱包中是否同时拥有一张10美元和一张5美元,或者钱包中包含三张5美元,只有这两种情况才能进行找零。

C++代码:

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0;
        for (auto x: bills) {
            if (x == 5) five++;
            else if (x == 10) {
                if (!five) return false;
                five--;
                ten++;
            }else {
                if (ten && five) ten--, five--;
                else if (five >= 3) five -= 3;
                else return false;
            }
        }
        return true;
    }
};

135. 分发糖果

题目链接

解题思路
该题采用贪心的策略,重点是一定要先确定一边之后,再确定另一边,如果在考虑局部的时候想两边兼顾,就会顾此失彼。
该题采用两次贪心的策略:

  • 首先从左向右遍历,比较右边孩子评分比左边高的情况,使得右边孩子的糖果比相邻的左边孩子糖果数多一。
  • 然后从右向左遍历,比较左边孩子评分比右边高的情况,那么如果左边孩子的评分高,在确定左边孩子糖果数时,需要将当前左边孩子的糖果数与右边孩子糖果数+1进行比较,取两者的最大值作为左边孩子的糖果数,这样就能满足相邻两个孩子评分更高的孩子会获得更多的糖果。

C++代码:

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> nums(ratings.size(), 1);
        // 从前向后
        for (int i = 1; i < nums.size(); i++) {
            if (ratings[i] > ratings[i - 1]) nums[i] = nums[i - 1] + 1;
        }
        // 从后向前
        for (int i = nums.size() - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) nums[i] = max(nums[i], nums[i + 1] + 1);
        }
        // 统计结果
        int res = 0;
        for (auto c: nums) res += c;
        return res;
    }
};

406. 根据身高重建队列

题目链接

解题思路
这道题与上一题分发糖果有一点点像,都涉及到两个维度,其技巧就是先确定一边然后贪心另一边,两边一起考虑,就会顾此失彼。
首先我们可以将序列按照身高h从大到小来排序,身高相同的话则k小的站前面,让高个子在前面。
这样做的目的主要是为了后边可以按照第二个维度k来将元素逐个重新插入到结果队列中。
优先按身高高的people的k来插入结果队列,后续插入的节点也不会影响前面已经插入的节点,最终按照k的规则完成了结果对列。

整个插入过程如下:

排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]

插入的过程:

  • 插入[7,0]:[[7,0]]
  • 插入[7,1]:[[7,0],[7,1]]
  • 插入[6,1]:[[7,0],[6,1],[7,1]]
  • 插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]
  • 插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]
  • 插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

此时就按照题目的要求完成了重新排列。

C++代码:

class Solution {
public:
    // 身高从大到小排(身高相同k小的站前面)
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        if (a[0] == b[0]) return a[1] < b[1];
        return a[0] > b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort (people.begin(), people.end(), cmp);
        list<vector<int>> que; // list底层是链表实现,插入效率比vector高的多
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1]; // 插入到下标为position的位置
            std::list<vector<int>>::iterator it = que.begin();
            while (position--) { // 寻找在插入位置
                it++;
            }
            que.insert(it, people[i]);
        }
        return vector<vector<int>>(que.begin(), que.end());
    }
};

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

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

相关文章

在Windows下安装PhantomJS和CasperJS及入门介绍(上)

近在使用Python爬取网页内容时&#xff0c;总是遇到JS临时加载、动态获取网页信息的困难。例如爬取CSDN下载资源评论、搜狐图片中的“原图”等&#xff0c;此时尝试学习Phantomjs和CasperJS来解决这个问题。这第一篇文章当然就是安装过程及入门介绍。 一. 安装Phantomjs 下载地…

SWUST派森练习题:P118. 数组接雨

描述 给定一个整形数组​​arr​​**&#xff0c;已知其中所有的值都是非负的&#xff0c;将这个数组看作一个柱子高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。​​(​​数组以外的区域高度视为​0)** 数据范围&#xff1a;数组长度​​** 0≤n≤…

wustojc2010两小时学完C语言

#include <stdio.h> int main() {int a,b,c;scanf("%d%d%d",&a,&b,&c);printf("%d",a-b*c);return 0;}

AUTOSAR规范与ECU软件开发(实践篇)4.5在Simulink中导入软件组件描述文件——“自上而下”的工作流程

“自上而下”的工作流程有别于“自下而上”的工作流程,其需要先在AAT(AUTOSAR Authoring Tool)工具(如ISOLAR-A)中完成软件组 件框架设计,并将软件组件arxml描述文件导入Matlab/Simulink完成内部 算法的实现,然后再通过Matlab/Simulink生成符合AUTOSAR规范的代 码及arxm…

js 获取页面的滚动高度

想要获取页面的滚动位置可以通过给window绑定滚动事件来实现。 window.addEventListener(scroll,()>{const n document.documentElement.scrollTopconsole.log(n);}) 通过该方法可以获取页面的当前位置&#xff0c;或者实现其他的效果&#xff0c;例如电梯导航

v-model原理

v-model本质上是一个语法糖&#xff0c;应用在输入框上&#xff0c;就是value属性 和input事件的合写 作用:提供数据的双向绑定—实现子组件 和父组件数据的双向绑定 数据变 视图跟着变 :value视图变 数据跟着变 input <input type"text" v-model"msg"…

漏洞指北-VulFocus靶场专栏-中级01

漏洞指北-VulFocus靶场专栏-中级01 中级001 &#x1f338;dcrcms 文件上传 &#xff08;CNVD-2020-27175)&#x1f338;step1&#xff1a;输入账号 密码burp suite 拦截 修改类型为 jpeg 中级002 &#x1f338;thinkphp3.2.x 代码执行&#x1f338;step1&#xff1a;burpsuite …

[保研/考研机试] KY11 二叉树遍历 清华大学复试上机题 C++实现

题目链接&#xff1a; 二叉树遍历_牛客题霸_牛客网编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以指针方式存储&#xff09;。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/43719512169254700747…

【Android】Mobile-Security-Framework-MobSF Manifest 静态扫描规则

前言 移动安全框架&#xff08;MobSF&#xff09;是一个自动化的一体化移动应用程序&#xff08;Android/iOS/Windows&#xff09;测试、恶意软件分析和安全评估框架&#xff0c;能够执行静态和动态分析。MobSF支持移动应用程序二进制文件&#xff08;APK、XAPK、IPA和APPX&am…

JavaScript:DOM (5) 节点的CRUD - 修改、删除

修改(替换)节点 替换子项 replaceChild()可以将指定元素的某个子节点换成新的节点&#xff0c;语法为指定元素.replaceChild(新节点, 旧节点)。 范例&#xff1a; 原始结构&#xff1a; <ul><li>第一项</li><li>第二项</li><li>第三项&l…

Python编程从入门到实践_8-8 用户的专辑_答案

Python编程从入门到实践_8-8 用户的专辑_答案 我也看了一些其他人的答案&#xff0c;很多的答案存在问题&#xff0c;每次调用函数 make_album() 后生成一个专辑字典会覆盖上次调用函数 make_album() 生成的字典&#xff0c;不符合题意。 我采取的解决方案是添加一个空列表 …

全局异常捕获

一、创建普获异常的类 二、定义异常处理器 定义全局异常处理器非常简单&#xff0c;就是定义一个类&#xff0c;在类上加上一个注解RestControllerAdvice&#xff0c;加上这个注解就代表我们定义了一个全局异常处理器。 在全局异常处理器当中&#xff0c;需要定义一个方法来捕…

第二章、应用层

文章目录 2.1 应用层原理2.1.1 网络应用程序体系结构2.1.2 进程通信2.1.3 可供应用程序使用的运输服务2.1.4 因特网提供的运输服务2.1.5 应用层协议 2.2.2 Web 和 HTTP2.2.1 HTTP概况2.2.2 非持续连接和持续连接2.2.3 HTTP报文格式2.2.4 用户与服务器的交互&#xff1a;cookie2…

华为ENSP网络设备配置实战6(简单的链路聚合)

题目要求 1、创建聚合组&#xff0c;添加端口成员 2、PC1网段为vlan10&#xff0c;PC2网段为vlan20 3、LSW1为核心网关设备&#xff0c;正确配置PC网关 4、PC1与PC2互通 解题过程 1.1、 按照拓扑图&#xff0c;各个设备起名 sys &#xff08;进入系统视图&#xff09; sy…

OpenCV4环境配置

0.安装mingw64 官网链接&#xff1a;mingw 安装红框标记下载免安装版本&#xff0c;解压可用。 将解压后的mingw64\bin添加到path环境变量cmd中输入gcc -v&#xff0c;出现下图所示即配置成功 1.下载OpenCV源码 源码下载 官网&#xff1a;Releases - OpenCV 运行下载好的ex…

负载均衡下的 WebShell 连接

目录 负载均衡简介负载均衡的分类网络通信分类 负载均衡下的 WebShell 连接场景描述难点介绍解决方法**Plan A** **关掉其中一台机器**&#xff08;作死&#xff09;**Plan B** **执行前先判断要不要执行****Plan C** 在Web 层做一次 HTTP 流量转发 &#xff08;重点&#xff0…

经典组合优化问题

本文根据学习进度不定时更新。 团问题 此处要理解"each pair of which is connected by an edge"的含义&#xff0c;这里的which指的是谁呢&#xff1f;肯定是vertices&#xff0c;即每一对定点都有一条边连接起来。 团问题是NPC问题。 团问题和定点覆盖问题、边覆盖…

LLM提示词工程和提示词工程师Prompting and prompt engineering

你输入模型的文本被称为提示&#xff0c;生成文本的行为被称为推断&#xff0c;输出文本被称为完成。用于提示的文本或可用的内存的全部量被称为上下文窗口。尽管这里的示例显示模型表现良好&#xff0c;但你经常会遇到模型在第一次尝试时无法产生你想要的结果的情况。你可能需…

22.0.6 LEADTOOLS 增加了 Python 支持 -Crack

LEADTOOLS 增加了 Python 支持 Python 开发人员现在可以利用 LEADTOOLS 技术&#xff0c;包括识别、多媒体和成像。 2023 年 7 月 18 日 - 16:40新版本 特征 添加了完整的 Python 支持 LEADTOOLS Python 支持包括高级图像处理功能、OCR、PDF、条形码识别和表单处理&#xff0c;…

FPGA原理与结构——RAM IP核原理学习

目录 一、什么是RAM 二、RAM IP介绍 1、RAM分类简介 2、可选的内存算法 &#xff08;1&#xff09;Minimum Area Algorithm&#xff08;最小面积算法&#xff09; &#xff08;2&#xff09;Low Power Algorithm &#xff08;低功耗算法&#xff09; &#xff08;3&#x…