1个n位正整数a,删去其中的k位,得到一个新的正整数b,设计一个贪心算法,对给定的a和k得到最小的b;
一.我的想法:先看例子:a=5476579228;去掉4位,则位数n=10,k=4,要求的最小数字b是n-k=6位的;
1、先找最高位的数,因为是6位数字,所以最高位不可能在后5位上取到(因为数字的相对顺序是不能改变的,假设如果取了后五位中倒数第5位的7,则所求的b就不可能是6位的了,最多也就是4位的79228)理解这点很重要!所以问题变成从第1位到第k+1(n-(n-k-1))取最小值,为什么是k+1,可以自己想一下。在这里就变成了
/54765/79228在斜杠中间选择最小的数字!
2、这样根据序号1,取得最小值4,那么最高位就已经确定了是4;然后6位的数就变为还有5位要确定,同上边的推理过程,次高位不可能取后4位中的任何数字,因为第一位确定了是第二位上的4,所以4之前的数字也不可能取到了(因为所求数字的相对顺序不能发生变化),所以变为求54/7657/9228中,斜杠之内的数字的最小值,得到是5。3、然后取第三位数字54765/79/228,第三位取7;547657/92/28第四位取2;54765792/2/8,第五位只能是2;第六位就是8;则所得数字就是457228;
4、继续想一个问题如果输入的整数a是3346579228,同样n=10,k=4;会遇到什么样的问题呢?同上边的过程第一步:/33465/79228,此时区间内有两个相同的最小值3,该用哪个值呢?很明显应该选取第一个3,why?因为试想如果取第二个则,第二次就只能在4657中选择最小值,而取第一个3,则可以再34657中取得3。
5、这个算法思路大概就是这样的,算法具体该怎么实现呢?首先我们要知道程序体要循环n-k次,因为只有这样我们才能每次循环取出最小的数字;其次就是怎么取区间内的最小值。我这里用的是通过循环遍历整个区间取得最小值,最关键的是确定区间的起始位置,第一次循环的位置最好确定就是1,结束位置就是k+1,第二次循环的起始位置是第一次取出的最小值的坐标值加1,结束位置是k+2;然后继续记录最小值的坐标值,以计算下一次的起始位置。
6、这是我的代码:
#include<iostream>
using namespace std;
int main(){
int num,k,n=0,a[100],x;
cin>>num>>k;
x=num;
//计算length(a);
while(x>0){
x=x/10;
n++;
}
a[0]=0;
//将输入的整形数字,存入定义的数组中;
for(int i=n;i>0;i--)
{
int s=num%10;
a[i]=s;
num=num/10;
}
int j,p=0,minn[n-k+1],min,q;
minn[0]=0;
for(int i=1;i<=n-k;i++)//n-k次循环;
{
min=a[p+1];
//定义q记录坐标;min[]记录每次所取的最小值
q=p+1;
for(j=p+1;j<=k+i;j++){
if(a[j]<min)
{
min=a[j];
q=j;
}
}
p=q;
minn[i]=min;
}
for(int i=1;i<=n-k;i++){
cout<<minn[i];
}
return 0;
}
原文地址:https://www.cnblogs.com/qichunlin/p/8127755.html