PAT 数字黑洞

给定任一个各位数字不完全相同的 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;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值