贪心系列专题篇四

news2024/10/1 3:35:17

​​​​​​​

目录

整数替换

解法一

解法二

俄罗斯套娃信封问题

堆箱子

可被三整除的最大和

距离相等的条形码

重构字符串


声明:接下来主要使用贪心法来解决问题!!!

整数替换

题目

思路

下面将使用两种方法来解决这道题,第一种方法是递归+记忆化搜索;第二种方法是贪心。

解法一

使用递归+记忆化搜素来解决,因为递归当对数进行两种操作时,会用到相同的值,因此记录下每个数的最小替换次数将会更佳。

代码

class Solution {
public:
    int integerReplacement(int n) {
        return dfs(n);
    }

    int dfs(long long n){
        if(n==1)
            return 0;
        if(n%2==0)
            return 1+dfs(n/2);
        else
            return 1+min(dfs(n+1),dfs(n-1));
    }
};//只递归版



class Solution {
    unordered_map<int,int> hash;
public:
    int integerReplacement(int n) {
        return dfs(n);
    }

    int dfs(long long n){
        if(hash.count(n))
            return hash[n];
        if(n==1){
            hash[1]=0;
            return hash[1];
        }
        if(n%2==0){
            hash[n]=1+dfs(n/2);
            return hash[n];
        }
        else{
            hash[n]=1+min(dfs(n+1),dfs(n-1));
            return hash[n];
        }
    }
};//递归+记忆化搜素
解法二

依题意,对于偶数,只执行除2操作,对奇数有+1和-1操作,那么如何能区分出+1和-1哪个操作更优那?

将奇数分成3类进行讨论:分别是3,大于3且模4等于1,大于3且模4等于3.

贪心策略

对于3,最少操作次数确定为2;

对于大于3且模4等于1,易知进行-1操作优于+1操作;

对于大于3且模4等于3,易知进行+1操作优于-1操作;

代码

class Solution {
public:
    int integerReplacement(long long 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){
                    n-=1;
                    ret++;
                }
                else if(n%4==3){
                    n+=1;
                    ret++;
                }
            }
        }
        return ret;
    }
};
俄罗斯套娃信封问题

题目

思路

首先我们先对集合按区间左端点进行排序,因为如果不排序的话,比较两个区间左端点的大小是需要不断遍历集合的。

通过分析这道题,我们会发现就是要找出一个最长的俄罗斯套娃序列即可,与《最长递增子序列》几乎是如出一辙,可以使用动态规划和定义排序+贪心+二分来解决,但是使用动态规划的时间复杂度是O(N^2),对于本道题是会超时的,下面将使用定义排序+贪心+二分来解决,时间复杂度是O(N^logN)的,贪心+二分是怎样的,如下:
我们知道,对于一个递增子序列,如果递增子序列某个位置的数在原始数组中该数后面的数比它小,那么可以以这个较小的数替换它,显而易见是可以的,不过这样找出来的结果虽然不是对应的最长递增子序列所对应的数,但是长度是一致的。

更新规则如下:从前往后扫描数组,当找到的数大于已记录的数,就把这个数放到长度更长的对应位置;如果找到的数大于某个位置的数,就往后找到合适的位置;当找到的数小于等于某个位置的数,就覆盖这个位置的数。

优化:扫描整个数组是必不可少的,可优化的地方就是找对应合适的位置,可使用二分查找代替再次遍历整个数组。

但是为什么要定义排序那?因为按常规排序时,得到的序列是如下图第一行所示,

因为已经排好序,因此我们只需要考虑每个二元组的第二个元素即可,和《最长递归子序列》一样;但是如果像下图第二行,就不行了,如果两个二元组的第一个元素相等,只考虑每个二元组的第二个元素,找出的结果可能不符合,因为题目要求外层的信封的宽度和高度都大于里层的信封的高度和宽度,解决办法,将二元组的第一个元素按升序进行排序,如果两个二元组的第一个元素相等,则将这类二元组的第二个元素按降序排序即可,如下面第二张图:

代码

class Solution {
public:
    int maxEnvelopes(vector<vector<int>>& envelopes) {
        int n=envelopes.size();
        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> v;
        v.push_back(envelopes[0][1]);
        for(int i=1;i<n;i++){
            if(envelopes[i][1]>v.back())
                v.push_back(envelopes[i][1]);
            else{
                int left=0,right=v.size()-1;
                while(left<right){
                    int mid=(left+right)>>1;
                    if(v[mid]<envelopes[i][1])
                        left=mid+1;
                    else
                        right=mid;
                }
                v[left]=envelopes[i][1];
            }
        }
        return v.size();
    }
};
堆箱子

题目

思路

首先我们先对集合按区间左端点进行排序,因为如果不排序的话,比较两个区间左端点的大小是需要不断遍历集合的。

通过分析这道题,我们会发现就是要找出一个最长的升序序列即可,与《最长递增子序列》几乎是如出一辙,可以使用动态规划和定义排序+贪心+二分来解决,使用动态规划的时间复杂度是O(N^2)。

代码

class Solution {
public:
    int pileBox(vector<vector<int>>& box) {
        int n=box.size();
        sort(box.begin(),box.end());
        vector<int> dp(n);
        for(int i=0;i<n;i++){
            dp[i]=box[i][2];
            for(int j=0;j<i;j++){
                if(box[i][0]>box[j][0] && box[i][1]>box[j][1] && box[i][2]>box[j][2])
                    dp[i]=max(dp[i],dp[j]+box[i][2]);
            }
        }
        return *max_element(dp.begin(),dp.end());
    }
};
可被三整除的最大和

题目

思路

贪心策略

如果我们通过拼凑若干个数来找到可被三整除的最大和是较为困难的,此时我们不妨尝试“正难则反”,先求出所有数的和,看是否能被三整除,如果能被三整除的话,所有数的和肯定是最大的值;如果不能被三整除的话,就删除某些数,如果总和模3余1,要么删除1个模3等于1的数,要么删除两个数的和模3等于2的数中最小的和次最小的数;如果总和模3余2,要么删除1个模等于2的数,要么删除两个数的和模3等于1的数中最小的和次最小的数。

寻找数组中最小和次最小的数,要么对数组排序的方式找,时间复杂度是O(N^logN),要么遍历整个数组,使用两个变量来记录数组中最小和次最小的数,时间复杂度是O(N),更优。

代码

class Solution {
public:
    int maxSumDivThree(vector<int>& nums) {
        const int INF=0x3f3f3f3f;
        int sum=0,x1=INF,x2=INF,y1=INF,y2=INF;
        for(int x:nums){
            sum+=x;
            if(x%3==1){
                if(x<x1)
                    x2=x1,x1=x;
                else if(x<x2)
                    x2=x;
            }
            else if(x%3==2){
                if(x<y1)
                    y2=y1,y1=x;
                else if(x<y2)
                    y2=x;
            }
        }
        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);
    }
};
距离相等的条形码

题目

思路

首先统计出现次数最多的数出现的次数,因为题目保证存在答案,因此这个次数的值肯定小于等于(数组大小n+1)/2的。

贪心策略

我们先把出现次数最多的数进行摆放,把出现次数最多的数摆放在奇数位置处,然后再摆放剩下的其余的数,只需要摆放两遍即可,先把所有的奇数位置处摆放完,再摆放偶数处的位置,这样能保证相邻位置的两个数是不相同的。

代码

class Solution {
public:
    vector<int> rearrangeBarcodes(vector<int>& barcodes) {
        unordered_map<int,int> hash;
        int maxVal=0,maxCount=0;
        for(int x:barcodes){
            if(maxCount<++hash[x]){
                maxCount=hash[x];
                maxVal=x;
            }
        }
        int n=barcodes.size();
        vector<int> ret(n);
        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>=n) index=1;
                ret[index]=a;
                index+=2;
            }
        }
        return ret;
    }
};
重构字符串

题目

思路

这一道题和上一道题几乎是一模一样的,不同之处是这道题不一定能成功重排字符。

首先统计出现次数最多的字符出现的次数,这个次数的值可能小于等于(数组大小n+1)/2,也可能大于(数组大小n+1)/2,此时返回空串。

贪心策略

我们先把出现次数最多的字符进行摆放,把出现次数最多的字符摆放在奇数位置处,然后再摆放剩下的其余的字符,只需要摆放两遍即可,先把所有的奇数位置处摆放完,再摆放偶数处的位置,这样能保证相邻位置的两个字符是不相同的。

代码

class Solution {
public:
    string reorganizeString(string s) {
        int n=s.size();
        int hash[26];
        char ch;
        int maxCount=0;
        for(char c:s){
            if(maxCount<++hash[c-'a']){
                maxCount=hash[c-'a'];
                ch=c;
            }
        }
        if(maxCount>(n+1)/2) return "";
        else{
            string str(n,' ');
            int index=0;
            for(int i=0;i<maxCount;i++){
                str[index]=ch;
                index+=2;
            }
            hash[ch-'a']=0;
            for(int i=0;i<26;i++){
                for(int j=0;j<hash[i];j++){
                    if(index>=n) index=1;
                    str[index]=i+'a';
                    index+=2;
                }
            }
            return str;
        }
    }
};












// class Solution {
// public:
//     string reorganizeString(string s) {
//         int n=s.size();
//         unordered_map<char,int> hash;
//         char ch;
//         int maxCount=0;
//         for(char c:s){
//             if(maxCount<++hash[c]){
//                 maxCount=hash[c];
//                 ch=c;
//             }
//         }
//         string str;
//         if(maxCount>(n+1)/2) return str;
//         else{
//             str.resize(n);
//             int index=0;
//             for(int i=0;i<maxCount;i++){
//                 str[index]=ch;
//                 index+=2;
//             }
//             hash.erase(ch);
//             for(auto& [t,k]:hash){
//                 for(int i=0;i<k;i++){
//                     if(index>=n) index=1;
//                     str[index]=t;
//                     index+=2;
//                 }
//             }
//             return str;
//         }
//     }
// };

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

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

相关文章

【论文阅读】—RTDETR

《DETRs Beat YOLOs on Real-time Object Detection》 最近&#xff0c;基于端到端DETR取得了显著的性能。然而&#xff0c;DETR的高计算成本限制了它们的实际应用&#xff0c;并阻碍了它们充分利用无后处理&#xff08;如非最大抑制&#xff08;NMS&#xff09;&#xff09;的…

Windows下如何像linux一样查看GPU使用情况

在linux下&#xff0c;只要使用 nvidia-smi即可看到服务器中每块卡的使用情况 但是在windows下该如何查看显卡的使用情况呢 通过网上学习发现&#xff0c;windows下有一个叫nvidia-smi.exe的程序 找到它所在的路径&#xff0c;然后在命令行中进入到这个路径&#xff0c;然后…

文件上传漏洞-HackBar使用

介绍 HackBar 是一个用于浏览器的扩展插件&#xff0c;主要用于进行网络渗透测试和安全评估。它提供了一系列方便的工具和功能&#xff0c;可以帮助用户执行各种网络攻击和测试&#xff0c;包括 XSS、SQL 注入、CSRF、路径穿越等 下载地址 可以到github上面去下载&#xff0…

傅里叶级数的C语言验证

目录 概述 1 收敛性 1.1 收敛定理 1.2 理解收敛定理 2 傅里叶级数的应用 2.1 问题描述 2.2 实现方法 3 方波函数的傅里叶验证&#xff08;C语言实现&#xff09; 3.1 方波函数 3.1.1 编写方波函数 3.1.2 程序函数验证 3.2 傅里叶级数函数实现 3.2.1 编写傅里叶级…

Android 实现左侧导航栏:NavigationView是什么?NavigationView和Navigation搭配使用

目录 1&#xff09;左侧导航栏效果图 2&#xff09;NavigationView是什么&#xff1f; 3&#xff09;NavigationView和Navigation搭配使用 4&#xff09;NavigationView的其他方法 一、实现左侧导航栏 由于Android这边没有直接提供左侧导航栏的控件&#xff0c;所以我尝试了…

Frida Hook String构造函数

前言 在实际Android应用开发中&#xff0c;无论是使用多么复杂的算法对字符串进行加密&#xff0c;然而开发者常常会构造出字符串的实例。因此&#xff0c;我们可以通过使用Frida hook String类的构造函数来追踪这些实例的构造位置&#xff0c;然后可以通过构造实例的地方栈回…

Java GUI制作双人对打游戏源码以及应用程序分享

文章目录 前言一、可执行程序二、源码以及图片资源总结 前言 在之前的文章展示了如何构建一款双人对打游戏&#xff0c;博文链接如下&#xff1a; https://blog.csdn.net/qq_43646281/article/details/137748943?spm1001.2014.3001.5501 感兴趣的小伙伴可以再去回顾一下: 原文…

一分钟了解请求转发与重定向

目录 请求转发 重定向 请求转发 为了更好的了解请求转发&#xff0c;我们可以画出关系图&#xff1a; 请求转发的特征: 地址栏的地址不发生改变, 是请求的资源的url请求转发中, 是一次请求request域有效请求转发是在服务器端转发的, 请求转发资源只能是服务器内部资源 重定…

Pointnet++改进即插即用系列:全网首发FMB自调制特征聚合|即插即用,提升特征提取模块性能

简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入FMB,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三 1.理论介…

DS18B20数字温度传感器操作解析

文章目录 引言特点工作原理引脚说明配置寄存器温度寄存器时序初始化时序写时序读时序 引言 DS18B20 是一种广泛使用的数字温度传感器&#xff0c;具有高精度和易用性。是Dallas Semiconductor公司&#xff08;现为Maxim Integrated公司&#xff09;生产的单总线数字温度传感器…

Typora+PicGo-Core(command line)+Gitee 实现上传图片到图床(看这一文就够)

前言 ​ 对于喜欢写Markdown文档的人来说&#xff0c;Typora无疑是一个写作利器&#xff0c;它有别于其他的Markdown软件&#xff0c;不是一边编辑一边渲染&#xff0c;而是即写即渲染&#xff0c;这样对于浏览md文件也非常友好。此外Typora还支持更换主题&#xff0c;在其官网…

机器学习 第10章-降维与度量学习

机器学习 第10章-降维与度量学习 10.1 k近邻学习 k近邻(k-Nearest Neighbor,简称kNN)学习是一种常用的监督学习方法其工作机制非常简单:给定测试样本&#xff0c;基于某种距离度量找出训练集中与其最靠近的k个训练样本&#xff0c;然后基于这k个“邻居”的信息来进行预测。通…

YOLOv5改进 | 多尺度特征提取 | 结合多样分支块及融合的高级设计(CVPR2021)

YOLOv5改进 | 多尺度特征提取 | 结合多样分支块及融合的高级设计&#xff09; 本文介绍论文原理介绍网络代码多种yaml设置网络测试及实验结果 本文介绍 YOLOv5&#xff08;You Only Look Once&#xff09;以其高效、准确的实时目标检测性能被广泛应用。然而&#xff0c;随着视觉…

【保姆级讲解C语言中的运算符的优先级!】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【Material-UI】使用指南:快速入门与核心功能解析

文章目录 一、快速入门1.1 安装和导入1.2 组件的独立性 二、全局设置2.1 响应式元标签2.2 CssBaseline2.3 默认字体 三、响应式设计3.1 Grid系统 四、最佳实践4.1 组件的一致性4.2 性能优化4.3 可访问性 五、总结 Material-UI是一个功能强大且灵活的React UI框架&#xff0c;为…

数学建模--二分法

目录 二分法的基本原理 应用实例 求解方程根 查找有序数组中的元素 注意事项 Python代码示例 ​编辑 延伸 二分法在数学建模中的具体应用案例有哪些&#xff1f; 如何选择二分法的初始区间以确保收敛速度和精度&#xff1f; 在使用二分法求解方程时&#xff0c;如何…

通过 ACM 论文模版学习 LaTeX 语法 【四、图】

文章目录 一、LaTeX 简介二、ACM 论文模版三、格式四、图和表4.1 图4.1.1. 导言区设置4.1.2. 插入图片的基本语法4.1.3. 设置图片的尺寸和位置4.1.4. 图片浮动体4.1.4.1. figure 环境4.1.4.2. 位置参数4.1.4.3. \centering4.1.4.4. \includegraphics4.1.4.5. \caption4.1.4.6. …

19061 简单加法

这个问题可以通过使用字符串处理和简单的数学运算来解决。我们可以首先将输入的字符串按照""字符进行分割&#xff0c;然后将分割后的每个字符串转换为整数并求和。 以下是使用C的代码实现&#xff1a; #include <iostream> #include <sstream> #inclu…

LeetCode刷题笔记 | 3 | 无重复字符的最长子串 | 双指针 | 滑动窗口 | 2025兴业银行秋招笔试题 | 哈希集合

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 这是一道银行的面试题&#xff0c;就是简单&#xff1f;&#xff01; LeetCode链接&#xff1a;3. 无重复字符的最长子串 1.题目描述 给定一个字符串 s &#xff0c…

live2d C++ sdk 分析

工具函数 首先会加载各种配置文件如model3.json&#xff0c;以字节流的方式读取(fstream) 读取过程中若报错 Stat failed. errno:2 path&#xff0c;很有可能是路径中出现了中文。因为官方用的stat函数判断文件合法性&#xff0c;stat函数貌似无法处理中文名 MatrixManager:…