贪心算法-删数问题C++

目录

一、题目

二:思路

 代码

运行结果


一、题目

有一个长度为n(n <= 240)的正整数,从中取出k(k < n)个数,使剩余的数保持原来的次序不变,求这个正整数经过删数之后最小是多少。

输入格式:
n和k

输出格式:
一个数字,表示这个正整数经过删数之后的最小值。

输入样例:

178543   4

结尾无空行
输出样例:

13

二:思路

思路:

对于删数问题,可以采用贪心算法来求解。贪心算法即每次都选择当前最优的方案,从而得到全局最优解。对于这道题,可以使用如下的贪心策略:

  1. 从左往右扫描数字,找到第一个比自己右侧数字大的数字,将该数字删除;
  2. 如果没有找到这样的数字,说明所有数字都是递增的,直接删除最后一个数字;
  3. 重复上述过程,直到删除了k个数字为止。
  4. 注意前导0的删除。

根据上述贪心策略,可以得到一个最小的新数字。
 


可以用坐标来形象表示过程:【每次删去最大数,再把剩下来的数连起来再删、再连,直到达到要求】

贪心算法实现 

  1. 定义一个字符串变量表示剩余的数字数字;
  2. 遍历每个数字,如果当前数字小于结果字符串的最后一个数字,那么就将结果字符串的最后一个数字删除,并将计数器加1;
  3. 将当前数字加入结果字符串;
  4. 如果计数器达到要删除的数字的数量时,就退出循环;
  5. 如果遍历完所有数字时,还没有达到要删除的数字的数量,就从结果字符串末尾删除数字直到满足要求;
  6. 如果结果字符串的所有数字都是0,就返回0;否则去掉前导零,并输出结果。

 代码

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string n;  // 原始数字n
    int k;     // 需要删除的数字个数
    while (cin >> n >> k)
    {
        string res = "";   // 存储最终结果
        int len = n.size(); // 数字n的长度

        // 假如需要删除的数字个数大于等于数字n的长度,直接输出0
        if (k >= len)
        {
            cout << 0 << endl;
            continue;
        }

        int cnt = 0;  // 记录已经删除的数字个数
        for (int i = 0; i < len; i++)
        {
            while (cnt < k && !res.empty() && res.back() > n[i])
            {
                // 如果需要删除的数字尚未全部删除,且新来的数字比当前的倒数第一个数字小
                // 就把最后一个数字删除,并将已删除数字个数加1
                res.pop_back();
                cnt++;
            }
            res.push_back(n[i]);  // 将新的数字添加到结果字符串中
        }

        // 如果需要删除的数字还没删除完,再从结果字符串末尾删除
        while (cnt < k)
        {
            res.pop_back();
            cnt++;
        }

        // 去掉前导零,并输出结果
        int i = 0;
        while (i < res.size() && res[i] == '0') i++;
        if (i == res.size()) cout << 0 << endl;
        else cout << res.substr(i) << endl;
    }
    return 0;
}

运行结果


只输入一遍【代码】

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string n;  // 原始数字n
    int k;     // 需要删除的数字个数
    cin >> n >> k;

    string res = "";   // 存储最终结果
    int len = n.size(); // 数字n的长度

    // 假如需要删除的数字个数大于等于数字n的长度,直接输出0
    if (k >= len)
    {
        cout << 0 << endl;
        return 0;
    }

    int cnt = 0;  // 记录已经删除的数字个数
    for (int i = 0; i < len; i++)
    {
        while (cnt < k && !res.empty() && res.back() > n[i])
        {
            // 如果需要删除的数字尚未全部删除,且新来的数字比当前的倒数第一个数字小
            // 就把最后一个数字删除,并将已删除数字个数加1
            res.pop_back();
            cnt++;
        }
        res.push_back(n[i]);  // 将新的数字添加到结果字符串中
    }

    // 如果需要删除的数字还没删除完,再从结果字符串末尾删除
    while (cnt < k)
    {
        res.pop_back();
        cnt++;
    }

    // 去掉前导零,并输出结果
    int i = 0;
    while (i < res.size() && res[i] == '0') i++;
    if (i == res.size()) cout << 0 << endl;
    else cout << res.substr(i) << endl;

    return 0;
}

运行结果

前导0的删除【测试】


1.

for (i = 0; (i < n.size() - 1) && (n[i] <= n[i + 1]); ++i);

for循环中的条件判断语句是判断n数组中相邻两个元素的大小关系,如果前一个元素小于等于后一个元素,则继续循环,否则跳出循环。循环结束后,i的值为最后一个满足条件的元素的下标加1。

这段代码是用来寻找最近的下降点的。

对于原始数字n,从左往右扫描每个数字,如果当前数字小于等于后面一个数字,说明在这个位置之前的数字都比后面的数字小或者相等,此时并没有出现下降,需要继续往后扫描。

当找到第一个当前数字大于后面一个数字的位置i时,说明在这个位置出现了下降,这个i就是最近的下降点。接下来就可以将i位置上的数字删除,达到删数的目的。

而这段代码的实现就是在循环中通过 i++ 不断向前扫描数字,直到找到下降点为止。同时,由于这里是使用分号结束 for 循环的,所以循环体内部的语句不会被执行,只有循环条件起到了作用。

综上所述,这段代码的作用是找到最近的下降点,从而实现删数问题的解决。

int i = 0;

while (i < n.size() && n[i] == '0') i++;

if (i == n.size()) cout << 0 << endl;

else cout << n.substr(i) << endl; 

这段代码用来删去剩余数字中的前导零,以保证输出的新数字是不含前导零的。

具体实现思路如下:

  1. 定义一个变量i,表示第一个非零数字的位置;
  2. 从左往右扫描每个数字,如果当前数字是0,就将变量i加1,继续往后扫描;
  3. 如果遇到第一个非零数字时,就退出循环;
  4. 如果所有数字都是0,则输出0;否则输出从第i个位置开始的所有数字。

在这段代码中,可以使用 while 循环来实现上述逻辑。首先将变量i初始化为0,然后循环遍历整个数字n。在循环内部,判断当前数字是否为0,如果是0,则将i加1,继续往后扫描;如果遇到第一个非零数字时,就退出循环。

在循环结束后,需要再次判断i和n.size()的关系,如果i等于n.size(),说明所有数字都是0,输出0即可;否则使用 n.substr(i) 函数截取从第i个位置开始到字符串末尾的子串并输出即可,这个子串就是不含前导零的新数字。

综上所述,这段代码的作用是完成前导零的删除,得到不含前导零的最终结果。

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string n;  // 原始数字n
    int k;     // 需要删除的数字个数
    cin >> n >> k;

    if (k >= n.size()) // 当要删除的数字个数k大于等于n的长度时,直接输出0
    {
        cout << 0 << endl;
        return 0;
    }

    while (k > 0)
    {
        // 寻找最近下降点
        int i;
        for (i = 0; (i < n.size() - 1) && (n[i] <= n[i + 1]); ++i);
        n.erase(i, 1);
        k--;
    }

    // 删去前导0
    int i = 0;
    while (i < n.size() && n[i] == '0') i++;
    if (i == n.size()) cout << 0 << endl;
    else cout << n.substr(i) << endl;

    return 0;
}

2.

    while (number.size() > 1 && number[0] == '0')
        number.erase(0, 1);
    cout << number << endl;

这段代码的作用是删除数字前面的所有前导零,以保证输出的数字没有前导零。

实现思路如下:

  1. 定义一个 while 循环,在循环内部检查当前数字是否存在前导零;
  2. 如果当前数字的位数大于1并且第一位是0,就将第一位删除;
  3. 继续往后扫描,直到不存在前导零为止。

在这段代码中,循环条件 number.size() > 1 && number[0] == '0' 表示当数字长度大于1并且第一个数字是0时,循环条件成立。循环体内部的 number.erase(0, 1) 语句表示删除从第一个位置开始的1个字符,即删除第一个数字。

这个循环会一直执行,直到不存在前导零为止。最终,输出的数字就是不含前导零的结果。

综上所述,这段代码的作用是删除数字前面的所有前导零,得到不含前导零的最终结果。

#include<iostream>
#include<string>
using namespace std;
int main() {
	string number;
	int k;
	cin >> number >> k;

	//有一个小问题。当要删除的数字个数k大于等于n的长度时,使用了number.erase()语句直接将原始数字全部删除,
	// 但这会导致程序在接下来的操作中出错。
	//if (k >= number.size())
	//	number.erase();

	if (k >= number.size()) // 当要删除的数字个数k大于等于n的长度时,直接输出0
	{
		cout << 0 << endl;
		return 0;
	}
	else
		while (k>0) {
			//寻找最近下降点
			int i;

			//for循环中的条件判断语句是判断number数组中相邻两个元素的大小关系,
			//如果前一个元素小于等于后一个元素,则继续循环,否则跳出循环。
			//循环结束后,i的值为最后一个满足条件的元素的下标加1。
			for (i = 0; (i < number.size() - 1) && (number[i] <= number[i + 1]); ++i);
			number.erase(i, 1);
			k--;
		}
	//删去前导0
	while (number.size() > 1 && number[0] == '0')
		number.erase(0, 1);
	cout << number << endl;
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用Python绘制六种可视化图表,简直太好用了

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python资料、源码、教程: 点击此处跳转文末名片获取 可视化图表&#xff0c;有相当多种&#xff0c;但常见的也就下面几种&#xff0c;其他比较复杂一点&#xff0c;大都也是基于如下几种进行组合&#xff0c;变换出来的。 …

记录--CSS 如何实现羽化效果?

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 最近碰到这样一个问题&#xff0c;在一张封面上直接显示书名&#xff0c;可能会存在书名看不太清楚的情况(容易受到背景干扰)&#xff0c;如下 为了解决这个问题&#xff0c;设计师提了一个“究极”方…

算法 - 希尔排序

原理 首先将数组两两分组&#xff0c;分成n组数组&#xff0c;每组数组内部进行排序。再分成n/2组数组&#xff0c;每组数组内部进行排序。直至分成只剩一组&#xff0c;最后进行排序得到最后的数组。 代码 public static int[] shell(int[] arr) {int temp;for (int gra …

计算机图形学13:三维图形的几何变换

作者&#xff1a;非妃是公主 专栏&#xff1a;《计算机图形学》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、三维图形的几…

MongoDB综述【入门指南】

写这篇博客,正好是2023年4月5日15:29:31,是清明节,放假一天,我坐在我的小小租房室内,思考着没思考到啥,哈哈哈,感觉好着急啊!看完了一本《城南旧事》,但是就是不踏实,好吧~我来写一篇最近在学的一个技术 为了更优秀的自己~奥利给!! 首先,我们从最初级小白开始(因为自己也是小白…

卷麻了,00后测试用例写的比我还好,简直无地自容.....

前言 作为一个测试新人&#xff0c;刚开始接触测试&#xff0c;对于怎么写测试用例很头疼&#xff0c;无法接触需求&#xff0c;只能根据站在用户的角度去做测试&#xff0c;但是这样情况会导致不能全方位的测试APP&#xff0c;这种情况就需要一份测试用例了&#xff0c;但是不…

倾斜实景三维建模与BIM模型处理技术

倾斜实景三维建模与BIM模型处理技术 一、研究背景 ➢ 倾斜模型 ✓ 真实纹理&#xff0c;高分辨率 ✓ 真实坐标&#xff0c;高空间精度 ✓ 快速建模&#xff0c;低建模成本 ➢ BIM设计 BIM 技术作为建筑施工行业中的新技术&#xff0c;存在于建筑的全生命周期&#xff0c;服务…

机器学习算法:K近邻(k-nearest neighbors)初探

KNN的介绍和应用 KNN&#xff08;K-Nearest Neighbor&#xff09;算法是一种基于实例的学习算法&#xff0c;也是一种常见的分类算法。 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别&#xff0c;则该样本也属于这个类别。 示例 &…

Python 3 基本数据类型,包含示例演示(初学友好)

嗨害大家好鸭~ 我是芝士❤ 有好好学习python吗&#xff1f; Python学习资料电子书 点击此处跳转文末名片获取 Python3 基本数据类型 Python 中的变量不需要声明。每个变量在使用前都必须赋值&#xff0c;变量赋值以后该变量才会被创建。 在 Python 中&#xff0c;变量就是变量…

MATLAB 求解定积分和不定积分

本文主要介绍如何通过matlab 去求解常见的定积分和不定积分的结果&#xff0c;使用matlab 内置函数 int。 语法&#xff1a; Fint(表达式&#xff0c;变量&#xff0c;变量上下限) 目录 例子1 单变量不定积分 例子2 多变量不定积分 例子3 单变量定积分 例子4 定积分近似求…

软件测试高频出现面试题-2(实用)

每日面试1、自我介绍2、简单介绍最近项目你是如何开展测试工作的呢&#xff1f;3、描述在这个项目里面你主要负责哪些模块的测试&#xff1f;选中一个业务复杂的讲述你是如何测试的呢&#xff1f;1、自我介绍 主要可以从三个方面准备&#xff1a;我的基础信息&#xff0c;我的…

OBCP第八章 OB运维、监控与异常处理-常见异常处理

问题排查概述&#xff1a;数据库连接问题排查 在遇到连接问题时&#xff0c;需要清楚整个系统的架构&#xff0c;对整个连接链路进行排查。通常情况下应用连接到数据库的完整链路是从应用服务器到 OBProxy 再到 OB 集群&#xff0c;此外还可能涉及负载均衡、DNS 解析、网络等。…

49天精通Java,第24天,Java链表、散列表、HashSet、TreeSet

目录一、链表二、散列表三、HashSet四、TreeSet五、TreeSet常用方法大家好&#xff0c;我是哪吒。 一、链表 从数组中间删除一个元素开销很大&#xff0c;其原因是向数组中插入元素时&#xff0c;此元素之后的所有元素都要向后端移动&#xff0c;删除时也是&#xff0c;数组中…

大厂面试篇--2023软件测试八股文最全文档,有它直接大杀四方

前言 已经到了金三银四的黄金招聘季节了&#xff0c;还在准备面试跳槽涨薪的小伙伴们可以看看本篇文章哟&#xff0c;这里呢笔者就不多说废话了直接上干货&#xff01;答案已整理好&#xff0c;文末拿去即可&#xff01;非常好用&#xff01; 一、字节跳动测试面经篇 1、在搜…

【KNN算法详解(用法,优缺点,适用场景)及应用】

KNN算法介绍 KNN&#xff08;K Near Neighbor&#xff09;&#xff1a;k个最近的邻居&#xff0c;即每个样本都可以用它最接近的k个邻居来代表。KNN算法属于监督学习方式的分类算法&#xff0c;我的理解就是计算某给点到每个点的距离作为相似度的反馈。 简单来讲&#xff0c;…

【工具】Maven

文章目录0.Maven安装&#xff08;不使用IDEA内置&#xff09;1.Maven的作用2.Maven核心概念3.maven目录结构4.仓库5.pom文件5.1 坐标 gav5.2.packaging5.3.依赖5.4.配置属性5.5.build6.Maven生命周期7.junit 单元测试8.插件9.IDEA构建Maven10.创建javase项目11.web工程12.依赖的…

【Linux】初识动静态库/动静态链接

文章目录动静态库的基本原理认识动静态库动静态库的特性手动安装静态库动静态库的基本原理 首先&#xff0c;文件和头文件最终变成一个可执行程序需要经历以下四个步骤&#xff1a; 1&#xff09;预处理&#xff1a;预处理所要完成的有&#xff0c;头文件展开、去注释、宏替换…

【HTML系列】第四章 · 列表和表格

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

【艾特淘】淘宝做爆款的目的是什么?怎么做?

其实在淘宝上面也有很多卖家都想要去打造属于自己店铺的爆款商品。 但是又不知道淘宝做爆款商品的目的是什么&#xff0c;也不知道爆款商品到底应该要怎么做&#xff0c;我马上就来给各位卖家介绍。 我们打造爆款是为了让我们通过爆款赚钱&#xff0c;通过爆款引来的流量带动其…

计算机| 关于CPU的12个知识点(图文详解)

CPU是什么&#xff1f; CPU与计算机的关系就相当于大脑和人的关系&#xff0c;它是一种小型的计算机芯片&#xff0c;通常嵌入在电脑的主板上。 CPU的构建是通过在单个计算机芯片上放置数十亿个微型晶体管来实现。 这些晶体管使它能够执行运行存储在系统内存中的程序所需的计…