【贪心算法】区间类算法题(整数替换、俄罗斯套娃、重构字符串等、C++)

文章目录

  • 1. 前言
  • 2. 算法题
    • 1.整数替换
    • 2.俄罗斯套娃信封问题
    • 3.可被三整除的最大和
    • 4.距离相等的条形码
    • 5.重构字符串

1. 前言

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

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

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

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

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


2. 算法题

1.整数替换

在这里插入图片描述

思路

题目求解将整数 n 转换为 1 的最小操作次数。操作可以是将 n 变为 n/2(当 n 是偶数时)或将 n 增加或减少 1(当 n 是奇数时):

  1. 如果 n 是偶数:直接将 n 除以 2,并增加操作计数 ret
  2. 如果 n 是奇数
    • 特例:当 n 是 3 时,直接将其变为 1,共需要两次操作。
    • 一般情况:根据 n 的末尾二进制位判断操作:
      • 末尾为 01n % 4 == 1,则将 n 减 1 并除以 2。
      • 末尾为 11n % 4 == 3,则将 n 加 1 并除以 2。

代码

class Solution {
public:int integerReplacement(int n) {// 贪心int ret = 0;while(n > 1){if(n % 2 == 0){n /= 2;++ret;}else{// 以二进制进行分析if(n == 3){ret += 2;n = 1;} else if (n % 4 == 1) { // ....01n = (n - 1) / 2;ret += 2;} else { // ...11n = n / 2 + 1;ret += 2;}}    }return ret;}
};

2.俄罗斯套娃信封问题

在这里插入图片描述

思路

题目要求解“俄罗斯套娃信封”问题,即找出能在彼此中嵌套的最大信封数目。核心思路是:贪心 + 二分

  1. 排序:首先对信封按左端点升序排序,如果左端点相同,则按右端点降序排序。这确保了左端点相同的信封不会嵌套。

  2. 贪心 + 二分搜索

    • 使用一个动态数组 ret 来存储当前有效的信封序列的右端点。
    • 遍历每个信封的右端点 b
      • 如果 b 大于 ret 的最后一个元素,表示可以将 b 追加到 ret 的末尾。
      • 否则,使用二分搜索在 ret 中找到第一个不小于 b 的位置,并替换该位置的值,以维持 ret 的非递减顺序。
  3. 返回结果ret 的大小即为最大嵌套信封的数目。

这个算法的时间复杂度为 O(n log n),其中 n 是信封的数量。

class Solution {
public:int maxEnvelopes(vector<vector<int>>& envelopes) {sort(envelopes.begin(), envelopes.end(), [&](const vector<int>& v1, const vector<int>& v2){// 左端点不同,则按左端点排序; 左端点相同,则按右端点排序降序return v1[0] != v2[0] ? v1[0] < v2[0] : v1[1] > v2[1];});// 贪心 + 二分优化vector<int> ret;ret.push_back(envelopes[0][1]);for(int i = 1; i < envelopes.size(); ++i){int b = envelopes[i][1];if(b > ret.back()){ret.push_back(b);}else{// 二分: 到第一个大于或等于当前元素的位置int left = 0, right = ret.size() - 1;while(left < right){int mid = (left + right) >> 1;if(ret[mid] >= b) right = mid;else left = mid + 1;}ret[left] = b;}}return ret.size();}
};

3.可被三整除的最大和

在这里插入图片描述

思路

题目要求计算一个数组 nums 中的最大和,使其能被3整除。具体步骤如下:

  1. 初始化变量sum 记录数组总和,x1, x2 分别记录 %3 == 1 的最小和次小数,y1, y2 记录 %3 == 2 的最小和次小数。

  2. 遍历数组:累加 sum,同时更新 x1, x2, y1, y2 记录对应的最小值。

  3. 分类讨论

    • 如果 sum % 3 == 0,则 sum 已经可以被3整除,直接返回。
    • 如果 sum % 3 == 1,考虑去掉 %3 == 1 的最小值或去掉 %3 == 2 的最小两个值(以保证总和能被3整除),取两者的最大值。
    • 如果 sum % 3 == 2,类似地,考虑去掉 %3 == 2 的最小值或去掉 %3 == 1 的最小两个值,取两者的最大值。
  4. 返回结果:如果没有满足条件的结果,返回 -1

代码

class Solution {
public:int maxSumDivThree(vector<int>& nums) {const int INF = 0x3f3f3f3f;// x1,x2: 标记%3==1的数 的最小与次小数// y1,y2: 标记%3==2的数 的最小与次小数int sum = 0, x1 = INF, x2 = INF, y1 = INF, y2 = INF;for(auto num : nums){sum += num;if(num % 3 == 1){if(num < x1) x2 = x1, x1 = num;else if(num < x2) x2 = num;}else if (num % 3 == 2){if(num < y1) y2 = y1, y1 = num;else if(num < y2) y2 = num;}}// 分类讨论if(sum % 3 == 0) return sum;else if (sum % 3 == 1) return max(sum - x1, sum - y1 - y2);// else return max(sum - y1, sum - x1 - x2); else if (sum % 3 == 2) return max(sum - y1, sum - x1 - x2); return -1;}
};

4.距离相等的条形码

在这里插入图片描述

思路

题目要求重新排列 barcodes 中的元素,使得相同元素不相邻。下面是代码的步骤:

  1. 统计元素频率:使用 unordered_map 记录每个元素的出现次数,并找到出现次数最多的元素 maxVal 和其出现次数 maxCount

  2. 插入最多的元素:在结果向量 ret 的偶数位置(0, 2, 4, ...)中填充最多出现的元素 maxVal

  3. 插入其余元素:将其他元素插入到结果向量中,首先填充偶数位置后,如果偶数位置已满,则从奇数位置开始填充。

  4. 返回结果向量:生成的向量符合要求,即相同元素不相邻。

代码

class Solution {
public:vector<int> rearrangeBarcodes(vector<int>& barcodes) {unordered_map<int, int> hash; // 用于记录出现次数最多的那个数int maxVal = 0, maxCount = 0;for(auto x : barcodes){if(maxCount < ++hash[x])maxVal = x, maxCount = hash[x];}// 插入出现次数最多的那个元素maxValvector<int> ret(barcodes.size());int index = 0;for(int i = 0; i < maxCount; ++i){ret[index] = maxVal;index += 2;}// 插入其余元素hash.erase(maxVal);for(auto [a, b] : hash){// 根据每一位的次数插入for(int i = 0; i < b; ++i){// 超出数组范围后从奇数开始插入元素if(index >= barcodes.size()) index = 1;ret[index] = a;index += 2;}}return ret;}
};

5.重构字符串

在这里插入图片描述

思路

题目要求重排字符串 s,使得相同字符不相邻。代码步骤如下:

  1. 统计字符频率:使用 unordered_map 记录每个字符的出现次数,并找出出现次数最多的字符 maxCh 和其出现次数 maxCount

  2. 检查可重排性:如果 maxCount 超过 (n + 1) / 2,则无法重排,直接返回空字符串。

  3. 填充结果字符串

    • 处理最多的字符:首先将出现次数最多的字符 maxCh 插入到结果字符串的所有偶数位置(0, 2, 4, ...)。
    • 处理其余字符:将其余字符插入到结果字符串的空闲位置中,先填充偶数位置,如果偶数位置填满,则转到奇数位置。
  4. 返回结果字符串:生成的字符串符合要求,确保相同字符不相邻。

代码

class Solution {
public:string reorganizeString(string s) {unordered_map<char, int> hash; // 统计字符以及出现次数// 找出现次数最多的字符char maxCh = ' '; int maxCount = 0, n = s.size();for(auto ch : s){if(maxCount > (n + 1) / 2) return ""; // 不能重构if(maxCount < ++hash[ch]){maxCount = hash[ch];maxCh = ch;}}// 处理出现次数最多的字符int index = 0;string ret(n, ' '); // 结果字符串for(int i = 0; i < maxCount; ++i){// ret.insert(index, 1, maxCh);ret[index] = maxCh;index += 2;}// 处理其余字符hash.erase(maxCh);for(auto [a, b] : hash){// 对每个元素进行次数插入for(int j = 0; j < b; ++j){if(index >= n) index = 1;ret[index] = a;index += 2;}}return ret;}
};

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

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

相关文章

anolis 8 安装部署spdk

SPDK的部署可以参考官方 https://github.com/spdk/spdk 有文档 这里记录一下&#xff0c;基于 Anolis OS release 8.6 kernel 5.10.134-13.an8.x86_64v 下的部署以及遇到的问题 使用 v22 版本 &#xff0c; 这里会git clone github项目&#xff0c;国内访问github会失败&…

Elasticsearch数据写入过程

1. 写入请求 当一个写入请求&#xff08;如 Index、Update 或 Delete 请求&#xff09;通过REST API发送到Elasticsearch时&#xff0c;通常包含一个文档的内容&#xff0c;以及该文档的索引和ID。 2. 请求路由 协调节点&#xff1a;首先&#xff0c;请求会到达一个协调节点…

大数据决策分析平台建设方案(可编辑的56页PPT)

引言&#xff1a;在当今信息爆炸的时代&#xff0c;大数据已成为企业决策制定、业务优化与市场洞察的重要驱动力。为了充分挖掘大数据的潜在价值&#xff0c;提升决策效率与精准度&#xff0c;构建一套高效、灵活、可扩展的大数据决策分析平台显得尤为重要。通过大数据分析平台…

C++ 中的 vector 容器详解与应用示例

vector 是 C 标准模板库&#xff08;STL&#xff09;中最常用的顺序容器之一。与数组相比&#xff0c;vector 具有动态大小调整、内存自动管理等特点&#xff0c;极大地方便了日常编程工作。本文将从 vector 的基本用法、常用操作、具体示例等方面进行详细介绍。 1. vector 简介…

部分库函数及其模拟

前言&#xff1a;当我们学习c/c库函数的时候&#xff0c;我们可以用网站 cplusplus.com - The C Resources Network 来进行查阅&#xff0c;学习。 目录 库函数&#xff1a; 1.字符串函数 1.1求字符串长度 strlen 1.2长度不受限制的字符串函数 1.2.1strcpy 1.2.2strca…

vue3如何创建多环境变量

首先在全局目录中新建.env.development文件和.env.production文件、.env.test文件 .env.development文件 VITE_MODE_NAMEdevelopment VITE_API_URL"http://xxxxxxxxxx" 注意&#xff1a;必须要以VITE_ 去开头&#xff0c;否则获取不到 依次去配置.env.production文…

Pikachu靶场之RCE漏洞详解

一.exec "ping" 1.ping本机127.0.0.1 2.用&符拼接dir查看目录 3.&拼接echo输入一句话木马 127.0.0.1&echo "<?php eval($_POST[cmd]);?>)" > 6.php 4.同级目录访问6.php&#xff0c;蚁剑连接 二&#xff1a;exec "eval"…

c中 int 和 unsigned int

c语言中&#xff0c;char、short、int、int64以及unsigned char、unsigned short、unsigned int、unsigned int64等等类型都可以表示整数。但是他们表示整数的位数不同&#xff0c;比如&#xff1a;char/unisigned char表示8位整数&#xff1b; short/unsigned short表示16位整…

CATIA P3 V5-6R2020下载安装教程,附软件包百度网盘分享下载链接地址

CATIA V5软件介绍 CATIA V5 是达索系统公司开发的 CAD/CAE/CAM 一体化软件&#xff0c;在多行业广泛应用。它源于航空航天业&#xff0c;也是汽车工业事实标准。其发展历经多个版本&#xff0c;V5 版本界面友好且功能强大。 特点包括强大功能&#xff0c;如先进建模技术可创建…

Linux Vim的 命令大全

Linux Vim的 命令大全 文章目录 Linux Vim的 命令大全[TOC](文章目录)Vim 的历史Vi 的诞生Vim 的诞生Vim 的开源与发展Vim 的影响力1.Vim 的基本模式2. 正常模式常用命令3. 插入模式4. 命令模式5. 可视模式6. 其他有用的命令7. 自定义设置下载 Vim 的历史 Vim 的历史可以追溯到…

SD三分钟入门!秋叶大佬24年8月最新的Stable Diffusion整合包V4.9.7来了~

1 什么是 Stable Diffusion&#xff1f; Stable Diffusion&#xff08;简称SD&#xff09;是一种生成式人工智能技术&#xff0c;于2022年推出。它主要用于根据文本描述生成精细图像&#xff0c;同时也可应用于其他任务&#xff0c;如图像修补、扩展&#xff0c;以及在文本提…

C++ Windwos 文件操作

两种方式获取文件大小 INT64 MyGetFileSize(const CString& strFilePath) {//获取文件大小INT64 nLen 0;WIN32_FILE_ATTRIBUTE_DATA attr { 0 }; //文件属性结构体if (FALSE GetFileAttributesEx(strFilePath, GetFileExInfoStandard, &attr)) //获取文…

图论篇--代码随想录算法训练营第五十一天打卡| 99. 岛屿数量(深搜版),99. 岛屿数量(广搜版),100. 岛屿的最大面积

99. 岛屿数量&#xff08;深搜版&#xff09; 题目链接&#xff1a;99. 岛屿数量 题目描述&#xff1a; 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而…

FFmpeg源码:compute_frame_duration函数分析

一、compute_frame_duration函数的定义 compute_frame_duration函数定义在FFmpeg源码&#xff08;本文演示用的FFmpeg源码版本为7.0.1&#xff09;的源文件libavformat/demux.c中&#xff1a; /*** Return the frame duration in seconds. Return 0 if not available.*/ stat…

2025秋招NLP算法面试真题(十八)-大模型训练数据格式常见问题

目录: SFT(有监督微调)的数据集格式RM(奖励模型)的数据格式PPO(强化学习)的数据格式找数据集哪里找微调需要多少条数据有哪些大模型的训练集进行领域大模型预训练应用哪些数据集比较好1.SFT(有监督微调)的数据集格式? 对于大语言模型的训练中,SFT(Supervised Fine…

pycharm如何安装selenium

在pycharm中打开一个项目后,点击Setting(ALTCtrlS快捷键) 然后点击install package完成后点击关闭这个窗口,就可以在代码中使用selenium了 成功后出现如下界面 编写一段正常可以运行操作chorme浏览器的 from selenium import webdriver # 指定ChromeDriver的路径driver we…

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中…

SQL 编程基础

SQL&#xff08;结构化查询语言&#xff09;广泛应用于数据库操作&#xff0c;是每个程序员都需要掌握的技能之一。这篇文章将带你从基础入门&#xff0c;了解SQL编程中的常量、变量及流程控制语句。我们将采用简单易懂的语言&#xff0c;结合实际示例&#xff0c;帮助你轻松理…

Android 调试桥——ADB

文章目录 前言ADB 的主要功能设备连接与管理应用安装与卸载文件传输日志查看设备重启 常用命令连接方式有线无线注意点 前言 ADB&#xff08;Android Debug Bridge&#xff0c;安卓调试桥&#xff09;是 Android SDK 提供的一种命令行工具&#xff0c;用于在开发者的计算机和 …

Stable Diffusion训练LoRA模型参数详细说明(阿里巴巴堆友AI)

工具&#xff1a;线上模型训练堆友AI 一、训练参数 批量大小 (Batch Size) 作用&#xff1a;每次训练中使用的样本数量。参考值&#xff1a;可以从 8 到 64&#xff0c;取决于显存大小。 训练轮数 (Epochs) 作用&#xff1a;完整遍历训练数据的次数。参考值&#xff1a;通…