给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字。一直重复这样做,我们很快会停在有“数字黑洞”之称的 6174,这个神奇的数字也叫 Kaprekar 常数。
例如,我们从6767开始,将得到
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
… …
现给定任意 4 位正整数,请编写程序演示到达黑洞的过程。
输入格式:
输入给出一个 (0,10
4
) 区间内的正整数 N。
输出格式:
如果 N 的 4 位数字全相等,则在一行内输出 N - N = 0000;否则将计算的每一步在一行内输出,直到 6174 作为差出现
,输出格式见样例。注意每个数字按 4 位数格式输出
。
①由于需要将一个整数的各个数字进行排序,逐渐递减的数字将为第一个数,第二个数是逐渐递增的数字,所以我们这里主要利用到了桶排序
的思想,即定义一个长度为10的数组(0 ~ 9的数字),数组下标对应的就是一个数字,对应的值就是这个数出现的次数。从下标为0开始遍历,计算数字,得到的就是第二个数,即逐渐递增的数;下标从9开始遍历,计算数字,得到的就是第一个数,即逐渐递减的数
。
②将整数中的各个数字存放到桶中需要注意的是,它的循环条件不再是判断这个数是否为0了,(即这个数还有没有数字),而是循环4次,每一次都要将它的余数放到桶中
。如果不这样的话,就会存在这种情况:
输入的是0005的时候,如果循环条件是判断当前的数字是否为0,那么就会导致错误,因为这样的话,放入到桶中的只有一个数字5,最后输出的时候就会0005 - 0005 = 0000,但是如果是循环4次放入桶中的话,那么arr[0] = 3,arr[5] = 1,这时候第一个数字就是5000,第二个数字是0005,最后结果自然会和上面的不同。我就是在这里耗了好久,一直检查下面的代码是否有问题,最后通过在网上查找题解,在人家的题解的时候,咋一看思路都是一样的,为啥我的就不行咧?😭😭😭,后来休息之后更加耐心看人家的题解,才知道是这里出了问题。
完整代码:
#include<stdio.h>
void getArr(int arr[],int num){
int count = 0;
while(count < 4){
arr[num % 10]++;
num /= 10;
count++;
}
}
/*
int getA(int arr[],int len){
int i,j,a = 0,count;
for(i = len - 1,j = 0; i >= 0 && j < len; i--,j++){
count = arr[i];
while(count != 0){
a = a * 10 + i;
count--;
}
}
return a;
}
int getB(int arr[],int len){
int i,a = 0,count;
for(i = 0; i < len; i++){
count = arr[i];
while(count != 0){
a = a * 10 + i;
count--;
}
}
return a;
}
*/
void getNum(int arr[],int len,int *a,int *b){
int i,count,a1 = 0,b1 = 0;
for(i = len - 1; i >= 0; i--){
count = arr[i];
while(count != 0){
a1 = a1 * 10 + i;
count--;
}
count = arr[len - 1 - i];
while(count != 0){
b1 = b1 * 10 + (len - 1 - i);
count--;
}
}
*a = a1;
*b = b1;
}
int main(){
int n,total,i,a,b;
int arr[10] = {0};
scanf("%d",&n);
getArr(arr,n);
/*
a = getA(arr,10);
b = getB(arr,10);
*/
getNum(arr,10,&a,&b);
total = a - b;
/*
不可以这样写,如果这样写的话,就会导致后面出现total = 0的时候,不会立刻
结束程序
if(total == 0){
printf("%04d - %04d = %04d\n",a,b,total);
}else{
while(total != 6174){
printf("%04d - %04d = %04d\n",a,b,total);
for(i = 0; i < 10; i++) //重置桶
arr[i] = 0;
getArr(arr,total);
getNum(arr,10,&a,&b);//利用指针,从而只需调用一个方法,就可以第一个数和第二个数
total = a - b;
}
printf("%04d - %04d = %04d\n",a,b,total);
}
但是我们可以对这个代码进行修改,也是可以的。将他的循环条件变成了total
!= 0 && total != 6174,当total不等于0并且不等于6174的时候,那么继续循
环,否则就将对应的式字输出,程序结束。
while(total != 0 && total != 6174){
printf("%04d - %04d = %04d\n",a,b,total);
for(i = 0; i < 10; i++) //重置桶
arr[i] = 0;
getArr(arr,total);
getNum(arr,10,&a,&b);//利用指针,从而只需调用一个方法,就可以第一个数和第二个数
total = a - b;
}
printf("%04d - %04d = %04d\n",a,b,total);
*/
while(1){
printf("%04d - %04d = %04d\n",a,b,total);
if(total == 0 || total == 6174) //如果total = 0 或者6174的时候,程序结束
break;
for(i = 0; i < 10; i++) //重置桶
arr[i] = 0;
getArr(arr,total);
/*
a = getA(arr,10);
b = getB(arr,10);
*/
getNum(arr,10,&a,&b);//利用指针,从而只需调用一个方法,就可以第一个数和第二个数
total = a - b;
}
return 0;
}
运行结果: