目录
题目描述
键盘输入一个高精度的正整数n,去掉其中任意s个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的n和s,寻找一种方案使得剩下的数字组成的新数最小。
输出应包括所去掉的数字的位置和组成的新的整数(n不超过240位) 。
问题分析
在位数固定的前提下,让高位的数字尽量小,那么值就较小。
总目标:删除高位较大的数字,相邻两位比较。若高位比低位大,则删除高位。
实例1:n = 12345863,s = 3
n = | 1 | 2 | 4 | 3 | 5 | 8 | 6 | 3 |
4>3,删除4 |
1 | 2 | 3 | 5 | 8 | 6 | 3 | |
8>6,删除8 |
1 | 2 | 3 | 5 | 6 | 3 | ||
6>3,删除6 | 1 | 2 | 3 | 5 | ||||
相邻的数字只需要从前向后比较 |
实例2:n = 231183,s = 3
n = | 2 | 3 | 1 | 1 | 8 | 3 |
3>1,删除3 |
2 | 1 | 1 | 8 | 3 | |
2>1,删除2 |
1 | 1 | 8 | 3 | ||
8>3,删除8 | 1 | 1 | 3 | |||
当第i位与第i+1位比较,若第i位删除,则必须向前考虑第i-1位与第i+1位进行比较。 |
实例3:n = 123456,s = 3
n = | 1 | 2 | 3 | 4 |
5 | 6 |
相邻比较发现,一个数字都没有删除,所以这就要考虑将后3位删除。在删除过程中也可能有这种情况出现:132567-->12567 |
实例4:n = 120083,s = 3
n = | 1 | 2 | 0 | 0 | 8 | 3 |
2>0,删除2 |
1 | 0 | 0 | 8 | 3 | |
1>0,删除1 |
0 | 0 | 8 | 3 | ||
8>3,删除8 | 0 | 0 | 3 | |||
1、删除一些数字后,高位可能出现‘0’,直接输出这个数据不合理。要将结果中的数字‘0’全部删除掉再输出。 2、若全是‘000000’,则要保留最后一个‘0输出’。 |
数据结构设计
对于高精度整数,可以将其存储为字符串格式。
算法设计
由实例归纳算法。
算法注意由4部分组成:初始化,相邻数字比较(必要时删除),处理比较过程中删除位数不够s位情况和结果输出。
其中删除字符的实现方法很多:如
1.物理的进行字符删除,就是用后面的字符覆盖已删除的字符,字符串的长度改变,这样可能会有较多的字符移动操作,算法效率不高。
2.可以利用数字记录字符的存在状态,元素值为“1”表示对应的数值存在,0表示不存在。 但这样做前后数字的比较过程和最后的输出过程相对复杂些。
3,利用一个数组,来记录为删除字符的下标。删除值时对应数组的下标删除。
代码编写
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Delete(char n[], int b, int k) {
int i;
printf("11111 strlen(n)= %2d\n", strlen(n));
for(i=b; i<=strlen(n)-k; i=i+1)
n[i]=n[i+k];
}
int main( ) {
char n[100]="12435833";
int s=3,i,j,j1,c,data[100],len;
printf("%c", n[8]);
len=strlen(n);
printf("$\n");
j1=-1; //记录上一个被删除的元素的位置,用来辨别是删除上一个被删除元素右边的元素还是左边的元素
for (i=0; i<s; i=i+1) {
int len1=strlen(n);
for (j=0; j<len1-1; j=j+1)
if (n[j]>n[j+1]) { //贪婪选择
Delete(n,j,1);
printf("##### j= %d j1= %d i= %d strlen(n)-1= %2d\n", j, j1, i, strlen(n)-1);
if (j>=j1) // 说明即将被删除的元素位于上一个被删除元素的右边
data[i]=j+i; //删除上一个被删除元素右边的元素 //记录删除数字位置
else //实例2向前删除的情况实例
data[i]=data[i-1]-1; ////删除上一个被删除元素左边的元素
j1=j;
break;
}
printf("j= %d j1= %d i= %d len1= %d strlen(n)= %d\n", j, j1, i, len1, strlen(n));
if( j>=len1-1) //说明在给定的序列中,任意相邻的两个元素,总是后面的元素大于前面的元素,
break; //即序列中的元素是按照从小到大排列的, 一旦是这种情况,就直接从后向前删除 s 位数即可。
}
printf("Output *** data[]:\n");
for (int i=0; i<s; i=i+1)
printf("%2d ", data[i]);
printf("22222 strlen(n)= %2d len= %d i= %d\n", strlen(n), len, i);
for (i=i; i<s; i=i+1) { //当序列中的元素是有序(从小到大排列)的, 直接从后向前删除 s 位数即可。
j=len-1-i;
Delete(n,j,1);
data[i]=j;
}
while (n[0]=='0' && strlen(n) >1)
Delete(n,0,1);
//将字符串首的若干个“0”去掉 print(n);
printf("Output array data[]:\n");
for (i=0; i<s; i=i+1)
printf("%2d ", data[i]);
printf("\n Output array n[]:\n");
printf("33333 strlen(n)= %2d\n", strlen(n));
for (i=0; i<strlen(n); i=i+1)
printf("%c ", n[i]);
system("pause");
return 0;
}
打印结果