【贪心算法】C++ 解决算法题:买卖股票 / K次取反 / 按身高排序 / 优势洗牌

1. 前言

1.1 贪心算法介绍

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下最优决策的算法。贪心算法通常用来解决最优化问题,其核心思想是通过局部最优解逐步推导出全局最优解。

在贪心算法中,我们并不总是考虑到未来可能发生的情况,而是只关注当前的最优选择。这种贪心选择性质使得贪心算法特别适合解决那些具有最优子结构性质的问题,即局部最优解能够推导出全局最优解的问题。

贪心算法的基本思路可以总结为以下几步:

  1. 确定问题的最优子结构:问题的最优解可以通过子问题的最优解逐步推导得到。
  2. 构造贪心选择:在每一步都做出当前状态下的最优选择,即局部最优解。
  3. 证明贪心选择性质:证明每一步的贪心选择都是最优的,能够推导出全局最优解。

需要注意的是,贪心算法并不适用于所有的问题,因为并非所有问题都具有最优子结构性质。在某些情况下,贪心算法得到的结果可能并不是全局最优解,而只是一个较好的解。因此,在应用贪心算法时,需要仔细分析问题的特性,以确定贪心算法是否适用于该问题。

下面会介绍一些用贪心解决的算法题:

2. 算法题

2.1_买卖股票的最佳时机

在这里插入图片描述
分析:

  • 买卖股票类的问题首先有一个通用解法,就是动态规划(之前有写),这里用贪心解:
  • 题目要求最多只能进行一次交易,因此我们可以利用循环解题

思路:

  • 创建两个变量ret负责记录统计过的当前最大利润,以及一个minPrev用于记录最小的买入价格
  • 通过遍历数组,每次对两变量进行更新,最后的ret就是结果

代码:

class Solution {
public:int maxProfit(vector<int>& prices) {int ret = 0;for(int i = 0, minPrev = INT_MAX; i < prices.size(); ++i){ret = max(ret, prices[i] - minPrev); // 更新结果minPrev = min(minPrev, prices[i]);}return ret;}
};

2.2_买卖股票的最佳时机II

在这里插入图片描述

分析:

  • 本题与上一题的区别在于:上一题只有一次交易机会本题可以多次交易,但是不能同时进行多笔交易,必须保证当前未持股时才能买入。

思路:
在这里插入图片描述

  • 我们只要保证每次做到低进高出即可,即在递增起点买入,终点卖出;
    此时有两种解决方法:
    • ① 以天数为指标:遍历数组,只要出现递增,那么就将这段递增的值加入到结果ret中
    • ② 利用双指针:本质是一样的,int i遍历数组,当找到一处递增时,用指针j将该递增区间统计,当走出递增时,将i和j间的距离就是这一段的递增值(利润)

代码:

  • 利用天数:
class Solution {
public:int maxProfit(vector<int>& prices) {// 利用天计算int ret = 0, n = prices.size();for(int i = 1; i < n; ++i){if(prices[i] > prices[i-1])ret += prices[i] - prices[i-1];}return ret;}
};
  • 利用双指针:
class Solution {
public:int maxProfit(vector<int>& prices) {// 利用双指针int ret = 0, n = prices.size();for(int i = 0; i < n; ++i){int j = i;while(j + 1 < n && prices[j+1] > prices[j])j++;ret += prices[j] - prices[i];i = j; // 更新i到j+1}return ret;}
};

2.3_K次取反后最大化的数组和

在这里插入图片描述

分析:

  • 题目要求找到对整数数组nums的元素进行k次取反操作后的最大和,自然要先对负数取反,其次再对罪小的正数进行取反(贪心)

思路:

  • 首先统计负数的个数,先将可以反转的负从最小的进行开始反转,如果所有负数均反转,且仍k>0
  • 此时从小到大反转正数
  • (这个过程也可以通过一个priority_queue来完成)

代码:

class Solution {
public:int largestSumAfterKNegations(vector<int>& nums, int k) {int n = nums.size(), minElem = INT_MAX;int m = 0;for(auto x : nums) // 统计负数个数m{if(x < 0) ++m;minElem = min(minElem, abs(x)); // 找数组中绝对值最小的数}int ret = 0;if(m > k){sort(nums.begin(), nums.end());// 将前k小的负数转正,并统计到retfor(int i = 0; i < k; ++i)ret += abs(nums[i]);for(int i = k; i < n; ++i)ret += nums[i];}else // m == k: 将所有负数转正{// m < k:// 先将所有负数转正;后根据k-m的奇偶性进行编写for(auto x : nums)ret += abs(x);if((k - m) % 2) // 奇数 // 将当前数组的绝对值最小逆号ret -= minElem * 2;}return ret;}
};

2.4_按身高排序

在这里插入图片描述

分析:

  • 本质就是根据数组2的数据对数组1进行排序,可以利用vector 以及 pair<type, type> 二元组来完成;也可以创建一个下标数组,根据身高对下标数组进行排序,最后直接输出names[index[i]]

思路:

  • ① 创建一个vector<pair<int, string>> people,再将身高信息和姓名信息存放到该people进行降序排序
  • ② 创建并初始化一个下标映射的数组index,排序index(利用lambda表达式)根据身高信息逆序排序,最后返回姓名names[index[i]]

代码:

  • 利用二元组:
class Solution {
public:vector<string> sortPeople(vector<string>& names, vector<int>& heights) {// 利用二元组int n = names.size();vector<pair<int, string>> people;for (int i = 0; i < n; ++i) {people.push_back(make_pair(heights[i], names[i]));}// 根据身高降序sort(people.rbegin(), people.rend());// 提取结果vector<string> ret;for (const auto& p : people) {ret.push_back(p.second);}return ret;}
};
  • 利用下标数组:
class Solution {
public:vector<string> sortPeople(vector<string>& names, vector<int>& heights) {// 根据身高对下标进行排序: // 创建下标数组int n = heights.size();vector<int> index(n);for(int i = 0; i < n; ++i)index[i] = i;// 排序数组sort(index.begin(), index.end(), [&](const int i, const int j){return heights[i] > heights[j];});vector<string> ret;// 提取结果到数组for(int i = 0; i < n; ++i){ret.push_back(names[index[i]]);}return ret;}
};

2.5_优势洗牌

在这里插入图片描述

分析:

  • 要使优势最大,则应该尽量使用较小的大值(在nums1中找大于nums2[i]的最小值),类似田忌赛马的排列规则

思路:

  1. 首先对nums1进行排序(便于找大于nums2[i]的最小值),由于要根据nums2更改nums1,所以不能排序nums2,创建一个下标数组并根据nums2进行排序,就可以利用index按大小顺序访问nums2的元素
  2. 创建ret,用于存放nums1改变后的位置
  3. 遍历nums1,此时的思路就是田忌赛马的思路,对于当前元素(nums1未匹配的最小元素):
    • 如果大于nums2[index2[left]](当前最小元素),就直接匹配该元素
    • 如果小于nums2[index2[left]],那就匹配nums2的最大的元素

代码:

class Solution {
public:vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {// 1. 排序数组int n = nums1.size();sort(nums1.begin(), nums1.end());// 1.5 创建下标数组vector<int> index2(n);for(int i = 0; i < n; ++i)index2[i] = i;sort(index2.begin(), index2.end(), [&](const int i, const int j){return nums2[i] < nums2[j]; });// 2. 田忌赛马: 如果当前比得过,则插入当前位置// 如果比不过,则匹配对方最大的int left = 0, right = n-1;vector<int> ret(n);for(auto x : nums1){if(x > nums2[index2[left]]) ret[index2[left++]] = x;else ret[index2[right--]] = x;}return ret;}
};

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

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

相关文章

Java面试进阶指南:高级知识点问答精粹(一)

Java 面试问题及答案 1. 什么是Java中的集合框架&#xff1f;它包含哪些主要接口&#xff1f; 答案&#xff1a; Java集合框架是一个设计用来存储和操作大量数据的统一的架构。它提供了一套标准的接口和类&#xff0c;使得我们可以以一种统一的方式来处理数据集合。集合框架主…

云计算-交互式数据处理 (Interactive Data Processing)

AWS Glue DataBrew (AWS Glue DataBrew) 数据预处理是任何数据分析任务之前的重要步骤。AWS Glue DataBrew 是一个可视化工具&#xff0c;允许我们预处理数据&#xff0c;包括清洗和规范化数据。此AWS服务提供许多数据准备功能&#xff0c;包括分组、联接、过滤、重新采样、排序…

【数据结构(邓俊辉)学习笔记】二叉树04——Huffman树

文章目录 0. 概述1. 无前缀冲突编码2. 编码成本3. 带权编码成本4. 编码算法5. 算法实现流程6. 时间复杂度与改进方案 0. 概述 学习Huffman树。 1. 无前缀冲突编码 在加载到信道上之前&#xff0c;信息被转换为二进制形式的过程称作编码&#xff08;encoding&#xff09;&…

【随笔】Git 实战篇 -- Git Rebase出错?手把手教你如何优雅地解决常见问题 (四十二)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

JAVA系列:NIO

NIO学习 一、前言 先来看一下NIO的工作流程图&#xff1a; NIO三大核心组件&#xff0c;channel&#xff08;通道&#xff09;、Buffer&#xff08;缓冲区&#xff09;、selector&#xff08;选择器&#xff09;。NIO利用的是多路复用模型&#xff0c;一个线程处理多个IO的读…

探秘三相交流电子负载应用

三相交流电子负载是模拟实际负载的电子设备&#xff0c;主要用于电源、电机、变压器等产品的性能测试和老化试验。它能够精确控制电流、电压、频率等参数&#xff0c;模拟各种复杂的负载情况&#xff0c;为产品研发和质量控制提供可靠的测试手段。 三相交流电子负载在电源产品测…

#经验分享#笔记

一闪论文是一款专门用于论文写作、查重和降重的工具&#xff0c;被广泛认为是非常好用的。它可以帮助学生和研究者们更高效地撰写论文&#xff0c;并且确保内容的原创性。 首先&#xff0c;一闪论文具有强大的查重和降重功能。它可以快速准确地检测论文中的相似内容&#xff0…

4. 排序算法

文章目录 1.简单排序1.1 冒泡排序1.1.1 步骤核心思想1.1.2 参考代码1.1.3 时间复杂度1.1.4 空间复杂度1.1.5 优化 1. 2. 选择排序1.2.1 核心思想1.2.2 步骤1.2.3 参考代码1.2.4 时间复杂度1.2.5 空间复杂度1.2.6 优化 1.3 插入排序1.3.1 思想1.3.2 步骤1.3.3 参考代码1.3.4 时间…

JavaScript中的const关键字解析

在JavaScript中&#xff0c;const关键字用于声明常量&#xff0c;即那些一旦赋值后就不应更改的变量。它在许多方面与let关键字类似&#xff0c;但增加了一个重要的约束条件——必须在声明时初始化&#xff0c;并且之后尝试修改其值会导致错误。下面将深入探讨const的特性及其使…

js使用链表实现音乐播放器(新增,下一首播放,置顶,删除)

什么是链表 链表是一种线性数据结构&#xff0c;与数组类似&#xff0c;它用于存储一系列元素。不过&#xff0c;与数组在内存中连续存储元素不同&#xff0c;链表中的元素&#xff08;称为节点&#xff09;在内存中可以是非连续存放的。每个节点包含两部分&#xff1a;一部分…

Content-Type ‘application/x-www-form-urlencoded;charset=UTF-8‘ is not supported

前端向后端发送数据时候出现了这个问题&#xff0c;发现是内容类型的错误。浏览器的form表单默认 content-type类型为application/x-www-form-urlencoded &#xff1a; <form encType””>中默认的encType&#xff0c;form表单数据被编码为key/value格式发送到服务器&…

proxmox重装后挂载分区

主要是需要备份/etc/pve/storage.cfg storage dir: local path /var/lib/vzcontent vztmpl,iso,backup,imagesshared 0lvmthin: data1 thinpool data1vgname data1content images,rootdirnodes pve232,pve233,pve1dir: hdd1 path /mnt/pve/hdd1content rootdir,snippets,vztm…

Java开发的saas模式智能制造超强云MES系统源码springboot+mysql+uniapp一整套云MES系统源码

Java开发的saas模式智能制造超强云MES系统源码springbootmysqluniapp一整套云MES系统源码 智能制造超强云MES系统概述&#xff1a; MES以生产车间管理为核心&#xff0c;帮助企业实现生产动态监控和管理。把制造数据管理、计划排程管理、生产调度管理、库存管理、质量管理、人…

python小甲鱼作业001-3讲

0.Python是什么类型的语言 编译型语言不同&#xff0c;Python 代码在执行时由解释器直接逐行解释执行&#xff0c;无需先编译成机器语言。这使得开发过程更快&#xff0c;因为你可以即时运行并测试你的代码。 Python 在运行时自动推断变量的类型&#xff0c;无需在代码中显式声…

swagger-ui页面接口的入参出参与代码实体类不一致有差异、swagger请求实体与预期定义不符、swagger参数与实体中参数不一致原因分析

文章目录 一、问题背景二、问题原因及解决方法 一、问题背景 项目集成swagger之后&#xff0c;发现有个接口的请求跟接口对应不上&#xff0c;把其他接口的请求参数放到当前这个请求上了。 如下图&#xff1a;test1接口的请求参数是其他请求的&#xff0c;并不是test1接口的 …

win10如何查看本机ip地址?三招搞定,快来试试吧

在数字化时代&#xff0c;IP地址作为网络设备的唯一标识&#xff0c;对于计算机使用者来说具有重要意义。无论是为了进行网络设置、远程连接&#xff0c;还是解决网络问题&#xff0c;了解如何查看本机IP地址都是一项必备技能。对于使用Windows 10操作系统的用户来说&#xff0…

简单的 Cython 示例

1&#xff0c; pyx文件 fibonacci.pyx def fibonacci_old(n):if n < 0:return 0elif n 1:return 1else:return fibonacci_old(n-1) fibonacci_old(n-2) 2&#xff0c;setup.py setup.py from setuptools import setup from Cython.Build import cythonizesetup(ext_mod…

node.js(express)+MongoDB快速搭建后端---新手教程

前言&#xff1a; Node.js是一个基于 Chrome V8引擎的JavaScript运行环境&#xff0c;是对于前端工程师来说学习成本最小的后端实现方法&#xff0c;本篇文章总结如何从0-1写一个后端的登录接口 一、检查node环境 先检查自己的node是否安装 一般来说前端工程师的电脑环境肯定…

六面体大米装袋机在提升大米包装效率中的作用

在当今社会&#xff0c;随着科技的飞速发展&#xff0c;各行各业都在寻求创新与突破&#xff0c;以提升生产效率和降低成本。而在大米包装领域&#xff0c;六面体大米装袋机的出现&#xff0c;无疑为整个行业带来了革命性的变化。这种先进的机械设备不仅提高了大米的包装效率&a…

map转对象

import com.alibaba.fastjson.JSON;//转list集合 对象List<对象> listJSON.parseArray(JSON.toJSONString(mapLisr),对象.class);//转对象对象 对象 JSON.parseObject(JSON.toJSONString(map1), 对象.class);