【贪心算法指针】C++ 解决子数组 / 子序列的相关问题(最大数、数组和减半的最小操作数、连续/递增序列)

文章目录

  • 1. 前言
    • 1.1 贪心算法介绍
  • 2. 算法题
    • 2.1_将数组和减半的最少操作次数
    • 2.2_最大数
    • 2.3_最长递增子序列
    • 2.4_递增的三元子序列
    • 2.5_最长连续递增序列
    • 2.6_数组中的最长连续子序列
    • 2.7_在字符串中找出连续最长的数字串

1. 前言

1.1 贪心算法介绍

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

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

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

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

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

下面我们会解决一些 数组相关的算法题(子数组、子序列类问题)


2. 算法题

2.1_将数组和减半的最少操作次数

在这里插入图片描述

  • 题意分析:题目要求将数组nums的数组和至少减少一半的最少操作数
  • 思路分析:要求使数组和减少一半的最少操作,自然我们可以每次对最大的数进行减半操作(贪心),如何进行?—— 利用堆
    • 此时就有了思路:将数组元素加入到堆heap中,统计数组和的一半sum后,通过一个循环每次提取堆顶元素进行减半,直到sum<=0

代码:

class Solution {
public:int halveArray(vector<int>& nums) {priority_queue<double> heap;// 统计sumdouble sum = 0.0;for(auto x : nums){heap.push(x);sum += x; }sum /= 2.0;// 统计最少操作次数int count = 0;while(sum > 0){double tmp = heap.top() / 2;heap.pop();sum -= tmp;++count;heap.push(tmp);}return count;}
};

2.2_最大数

在这里插入图片描述

  • 题意分析:题目要求将给定的一组整数重排使其最大
  • 思路分析:要得到最大的重排结果,自然会想到将更大的数放到前面(贪心),这里如何排列顺序就是重点
    • 思路:
      • 将所给的数转为字符串,便于设定规则比较
      • 由于字符串是根据字典序比较的,“23” > “221”,排到前面,是和我们想要的规则一致的,则直接对字符串数组进行排序(根据两个元素的先后顺序大小)
      • 最后提取结果即可(注意全0的情况)

代码:

class Solution {
public:string largestNumber(vector<int>& nums) {// 将数字转换为字符串vector<string> strs;for(auto x : nums) strs.push_back(to_string(x));// 根据字符串排序// s1s2 > s2s1 则 s1s2在前,s2s1在后sort(strs.begin(), strs.end(), [&](const string& s1, const string& s2){return s1 + s2 > s2 + s1;});// 提取结果string ret;for(auto s : strs)ret += s;// 判断特殊情况:000000...->0if(ret[0] == '0') return "0";return ret;}
};

2.3_最长递增子序列

在这里插入图片描述

  • 题意分析:题目要找到数组的最长递增子序列的长度
  • 思路分析:首先对于这道题,是可以利用动态规划解题的;而对于贪心,我们可以用一个数组存放长度为n时的最后一位元素是什么,具体规则在下图:
    • 思路:
      在这里插入图片描述
    • 找ret中大于nums[i]的最小值的过程可以用二分查找进行优化

代码:

class Solution {
public:int lengthOfLIS(vector<int>& nums) {// 贪心vector<int> ret;ret.push_back(nums[0]);for(int i = 0; i < nums.size(); ++i){if(nums[i] > ret.back()) {ret.push_back(nums[i]);} else { // 二分查找int left = 0, right = ret.size() - 1;while(left < right){int mid = (left + right) >> 1;if(ret[mid] < nums[i])left = mid + 1;elseright = mid;}ret[left] = nums[i]; // 插入}}return ret.size();}
};

2.4_递增的三元子序列

在这里插入图片描述

  • 题意分析:题目要求找是否存在长度为3的递增子序列,实际上算是前面递增子序列的变体。
  • 思路分析:同理于上一题,首先可以使用动态规划解决,每次计算判断是否dp[i]为3即可,对于贪心,我们依然采取一样的策略,但可以进行优化
    • 思路:
    • 用变量a表示长度为1时的元素,变量b表示长度为2 的最后一位元素,遍历数组,只要存在一个nums[i] > b,就证明有长度为3的递增子序列

代码:

class Solution {
public:bool increasingTriplet(vector<int>& nums) {int a = nums[0], b = INT_MAX;for(auto x : nums){if(x > b) return true;else if (x > a) b = x;else a = x;}return false;}
};

2.5_最长连续递增序列

在这里插入图片描述

  • 题意分析:读题后发现,该题实际上就是找最长的递增子数组(子数组和子序列的区别就在于是否连续)
  • 思路分析:对于连续子数组,可以直接利用双指针进行解题:
    • 思路:
    • 创建两指针left、right
    • 遍历数组,如果出现递增则right++,否则就更新结果并将left移动到right位置,继续寻找;

代码:

class Solution {
public:int findLengthOfLCIS(vector<int>& nums) {vector<int> tmp(nums.begin(), nums.end());tmp.push_back(INT_MIN); // 用于简化特殊处理int ret = 0;int i = 0, j = 1; // 即left 于 rightwhile (i < tmp.size() && j < tmp.size()) {if (tmp[j - 1] < tmp[j]) {++j;} else {// 更新结果 + 移动 i 指针ret = max(ret, j - i);i = j; // 将 i 指针移到 j 的位置继续寻找连续递增子序列++j; // 同时移动 j 指针}}return ret;}
};

2.6_数组中的最长连续子序列

在这里插入图片描述

在这里插入图片描述

  • 题意分析:题目要求找到连续子序列,注意这里的连续要求的是值连续,位置不用连续(所以可以先进行排序、排序后本质就变成了子数组问题)
  • 思路分析:这道题可以使用哈希表;这里我们先排序、随后遍历数组,利用两个变量(curLen、maxLen)解题。
    • 思路:
    • 创建变量curLen(当前连续子序列的长度)、maxLen(连续子序列的最大长度)
    • 遍历数组,i指针用于遍历数组,当出现连续,则cur++,不连续就更新结果值max,并重置cur
    • (本质是和双指针一样的在这里插入图片描述

代码:

int MLS(vector<int>& arr) {sort(arr.begin(), arr.end());int curLen = 1, maxLen = 1;for (int i = 1; i < arr.size(); ++i){if (arr[i - 1] != arr[i]) // 不等于前一元素{if (arr[i - 1] + 1 == arr[i]) { // 连续curLen++;}else { // 不连续maxLen = max(maxLen, curLen);curLen = 1;}}}return max(curLen, maxLen);
}

2.7_在字符串中找出连续最长的数字串

在这里插入图片描述

  • 题意分析:题目要求找到字符串中的最长连续数字串,即最长的数字子数组
  • 思路分析:自然我们可以使用双指针来解题:
    • 思路:
    • i指针负责遍历数组,一直++,直到遇到数字串时,将j数组移动到i的位置用来遍历该数字串,走出数字串后更新结果
    • 需要注意的是该题会存在多个长度一样的数字串,所以需要用一个string数组来存储结果。

代码:

int findLongestNumSub() {string s;while (cin >> s) {int maxLen = 0; // 最长数字串的长度vector<string> substrings; // 存储最长数字串int i = 0, j = 0;while (i < s.size()) {while (i < s.size() && !(s[i] >= '0' && s[i] <= '9')) {++i;}j = i;while (j < s.size() && s[j] >= '0' && s[j] <= '9') {++j;}if (j - i > maxLen) {maxLen = j - i;substrings.clear();substrings.push_back(s.substr(i, maxLen));}else if (j - i == maxLen) {substrings.push_back(s.substr(i, maxLen));}i = j; // 移出数字串}for (const auto& sub : substrings) {cout << sub;}cout << "," << maxLen;cout << endl;} // end whilereturn 0;
}

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

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

相关文章

C-数据结构-树状存储的基本实现

/* 理解和记忆递归的关键在于把握递归的本质和函数调用的过程。递归函数在每次调用时会把当前状态压入调用栈&#xff0c;直到满足终止条件后开始回溯。理解基准条件和递归步骤&#xff1a;每个递归函数都需要有基准条件&#xff08;如节点为空时返回&#xff09;&#xff0c;并…

一文搞透常见的Python编码陷阱(上)(分析+案例)

一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 一、别忘了冒号 1. if 语句 2. while 语句 3. for 语句 4. 函数定义 5. 类定义 6. try/except 语句 …

STM32 HAL库串口空闲中断 + DMA 收发不定长数据

串口接收缓冲区定义 usart.h #define BUFFER_SIZE 64typedef struct {uint8_t buff[BUFFER_SIZE];uint32_t length;uint32_t rx_flag; }uart_rx_msg;/* 串口接收消息缓冲 */ extern uart_rx_msg rs422_rx_msg; extern uart_rx_msg rs485_rx_msg; extern uart_rx_msg rs232_r…

001 创建单例

文章目录 饿汉模式懒汉模式线程不安全懒汉式(线程安全)“双重检查锁定”&#xff08;Double-Checked Locking, DCL&#xff09;实现单例(线程安全)例子 1&#xff1a;两个线程几乎同时请求单例实例例子 2&#xff1a;多个线程在不同时间点请求单例实例例子 3&#xff1a;线程在…

IntelliJ IDEA工具的常用快捷键使用

1&#xff0e;单行注释&#xff1a; ctrl / 2. 多行注释&#xff1a; ctrl shift / 3&#xff0e;查看源码&#xff1a;按 ctrl 别松手&#xff0c;鼠标移动到对应的类名下方&#xff0c;出现下划线&#xff0c;点击过去&#xff0c;可以查看类源码。 4&#xff0e;多行编辑…

RTDETR结合CVPR2024最新图像增强算法!让你的模型无惧风雨【含端到端推理脚本】

如何有效地探索雨痕的多尺度表示对于图像去雨是很重要的。与现有的基于Transformer的方法相比,这些方法主要依赖于单一尺度的雨痕外观,我们开发了一个端到端的多尺度Transformer,利用各种尺度中潜在有用的特征来促进高质量的图像重建。为了更好地探索空间变化的雨痕的常见退…

el-table自定义表头数据不更新

我的表头是有三层的&#xff0c;中间一层展示对应的数据&#xff0c;所以需要自定义&#xff0c;官方的文档显示的写法如下&#xff1a; <el-table-column><template slot“header”><div>{{dayData.supply}}、{{dayData.use}}</div></template>…

Effective C++(1)

文章目录 1. 让自己习惯C条款1&#xff1a;视C为一个语言联邦条款2&#xff1a;尽量以const、enum、inline替换#define条款03&#xff1a;尽可能使用 const条款4&#xff1a;确保对象在使用之前被初始化 1. 让自己习惯C 条款1&#xff1a;视C为一个语言联邦 今天的C已经是多个…

原生html和js实现瀑布流布局(macyjs插件,不依赖于jquery,纯原生)

官网地址 方式一&#xff1a;在github上找到项目&#xff0c;复制demo/assets/css/macy.css&#xff0c;以及/dist/macy.js 直接引入项目 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv&qu…

如何理解类的符号引用?类的直接引用?

在Java中&#xff0c;符号引用&#xff08;symbolic reference&#xff09;和直接引用&#xff08;direct reference&#xff09;是理解Java类加载和内存管理的重要概念。它们涉及到JVM如何在运行时处理类、方法、字段等的引用。下面是对这两个概念的详细解释&#xff1a; 符号…

junit-platform-engine旧版本无法更新问题

现象&#xff1a; 运行groovy测试类&#xff0c;一直使用的是低版本的junit-platform-engine-1.5.2.jar。即使在最外层强制升级版本也没有用 解决&#xff1a; 在最外层pom.xml引入高版本的父pom即可 <dependencyManagement><dependencies><dependency>&…

满帮集团 Eureka 和 ZooKeeper 的上云实践

作者&#xff1a;胡安祥 满帮集团&#xff0c;作为“互联网物流”的平台型企业&#xff0c;一端承接托运人运货需求&#xff0c;另一端对接货车司机&#xff0c;提升货运物流效率。2021 年美股上市&#xff0c;成为数字货运平台上市第一股。根据公司年报&#xff0c;2021 年&a…

网络协议——FTP(简介、搭建FTP服务端)

一、简介 1、什么是FTP&#xff1f; FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09; TCP/IP 协议组的协议之一。常用20&#xff08;数据&#xff09;、21&#xff08;命令&#xff09;端口作为通讯端口。&#xff08;22为SSH端口&#xff09;F…

C++ 指针占用的大小是多少

作为一个C程序员&#xff0c;我们可以详细探讨指针在C中的大小&#xff0c;以及通过代码示例来演示这一点。 C 指针占用的大小是多少 指针的大小代码示例代码解释运行结果结论 指针的大小 指针的大小主要取决于系统的架构&#xff08;如32位或64位&#xff09;和编译器的实现…

就业班 第三阶段(ELK) 2401--5.22 day3 filebeat+elk云部署

kafka集群 Windterm同步输入&#xff0c;多台机子可以同时输入同步输入 启动kafka需要启动两个 第一个 [rootkafka1 ~]# cd /usr/local/kafka_2.11-2.0.0/ [rootkafka1 ~]# nohup bin/zookeeper-server-start.sh config/zookeeper.properties &第二个 [rootkafka1 ~]#…

apache BeanUtils

一、populate 1、介绍 BeanUtils.populate(Object bean, Map properties) 方法实在org.apache.commons.beanutils.BeanUtils包下的一个一个方法。 该方法的方法头 此方法中&#xff0c;有两个参数&#xff0c;Object bean 为一个实体类&#xff0c;Map properties为一个map集…

20232810 肖峰 2023-2024-2 《网络攻防实践》实验十一

一、实践内容 &#xff08;1&#xff09;web浏览器渗透攻击 任务&#xff1a;使用攻击机和Windows靶机进行浏览器渗透攻击实验&#xff0c;体验网页木马构造及实施浏览器攻击的实际过程。 实验步骤&#xff1a; ①选择使用Metasploit中的MS06-014渗透攻击模块 ②选择PAYLOAD为任…

Linux 36.3@Jetson Orin Nano之系统安装

Linux 36.3Jetson Orin Nano之系统安装 1. 源由2. 命令行烧录Step 1&#xff1a;下载Linux 36.3安装程序Step 2&#xff1a;下载Linux 36.3根文件系统Step 3&#xff1a;解压Linux 36.3安装程序Step 4&#xff1a;解压Linux 36.3根文件系统Step 5&#xff1a;安装应用程序Step …

# Mybatis 高级用法和tk.mybatis使用

Mybatis 高级用法和tk.mybatis使用 文章目录 Mybatis 高级用法和tk.mybatis使用使用SelectProvider、InsertProvider、UpdateProvider、DeleteProviderSelectProvider使用例子 tk.mybatis引入依赖查询实现实体映射类实体类规范 dao层调用dao 使用SelectProvider、InsertProvide…

eBay运营账号防关联成功的关键因素是什么?

一、什么是ebay eBay如今的发展现状呈现出积极且充满活力的态势。作为全球知名的在线拍卖和购物平台&#xff0c;随着全球消费者对线上购物的需求不断增长&#xff0c;这为卖家提供了广阔的市场空间和盈利机会&#xff0c;但多账号的运营若处理不好容易引起账号被关联&#xf…