神奇的利克瑞尔数:196 【大数加法】【回文数】

微信搜索:编程笔记本
微信搜索:编程笔记本
微信搜索:编程笔记本

点击上方蓝字关注我,我们一起学编程
欢迎小伙伴们分享、转载、私信、赞赏

今天要跟小伙伴们分享神奇的数字:196
在介绍这个神奇的数字之前,我们先来回顾一下回文数

回文数:正读与倒读为同一个数字。 譬如,12321 就是一个回文数。

这个神奇的数字就与回文数有关。有人发现,**几乎所有的自然数,将其自身与自身的倒序数相加,再对得到的和重复这一过程,最终总会得到一个回文数。**不同的数字所需要的循环次数不同。

  • 12 只需 1 步即可得到相应的回文数:12 + 21 = 33
  • 156 需要 3 步才能得到相应的回文数:156 + 651 = 807807 + 708 = 15151515 + 5151 = 6666

到目前为止,人类计算能力所能发现的需要最多循环次数的数为 1186060307891929990 ,它需要循环操作 261 次才能得到回文数。

下面该 196 登场了!

就是这么一个不起眼的数字,似乎打破了上面所描述的近乎完美的数字规律。曾经,有人将其运算了将近 7 万步,仍未能活得到其回文数。后来,有人修改了算法,更是算到了 2.89 亿步,仍然没能找到回文数。这就是一个著名的利克瑞尔数

利克瑞尔数(Lychrel Number)指的是将该数与将该数各数位逆序翻转后形成的新数相加、并将此过程反复迭代后,结果永远无法是一个回文数的自然数。


利克瑞尔数的介绍到底就结束了,不知道各位小伙伴们有没有一种意犹未尽的感觉呢?是不是少了点什么?
对嘛,写个程序跑一下嘛!

微信搜索:编程笔记本
微信搜索:编程笔记本
微信搜索:编程笔记本

首先,我们需要一个获取逆序数的子程序

int reverse(int positive)
{
    int last_digit;
    int reverse_num = 0;

    while (positive) {
        last_digit = positive % 10;

        reverse_num *= 10;
        reverse_num += last_digit;

        positive /= 10;
    }

    return reverse_num;
}

有了这个子程序后,我们就能很轻松地对一些数字进行验证了,

#include <stdio.h>

int main()
{
    int num;
    int step = 0;

    printf("Please input the number: ");
    scanf("%d", &num);

    while (num != reverse(num)) {
        num += reverse(num);
        ++step;
    }

    printf("Find palindrome %d with %d step(s)\n", num, step);

    return 0;
}

我们用 156 来测试一下:

➜  Lychrel gcc -o test test.c 
➜  Lychrel ./test 
Please input the number: 156
Find palindrome 6666 with 3 step(s)

可以看到,跟我们上面计算的结果一致。我们接着来测试一下 1186060307891929990 。

Please input the number: 1186060307891929990
Find palindrome -914565419 with 2 step(s)

微信搜索:编程笔记本
微信搜索:编程笔记本
微信搜索:编程笔记本

怎么肥四???这明显不对啊!

原来,由于 int 型数据的表示范围有限,导致程序不能正确处理数据及其和,最终导致错误的结果。

于是我准备将 int 换成 unsigned long long ,仔细一想这样也是不够的,整型数据类型总是只能表示有限的数据,所以我们需要一个表示无限数据的类型:字符串

因此,我们需要重新定义字符串整数的加法运算

void add(char **str1, char **str2)
{
    char *num1 = *str1;
    char *num2 = *str2;
    int len1 = strlen(num1);
    int len2 = strlen(num2);
    int carry = 0;
    int sum;

    if (len2 > len1) {
        swap(&num1, &num2);
        swap(&len1, &len2);
    }

    for (int i = 0; i < len2; ++i) {
        sum = (num1[len1 - i - 1] - '0') + (num2[len2 - i - 1] - '0') + carry;

        if (sum >= 10) {
            carry = 1;
            num1[len1 - i - 1] = sum - 10 + '0';
        } else {
            carry = 0;
            num1[len1 - i - 1] = sum + '0';
        }
    }

    if (carry == 1) {
        for (int i = 0; i < len1 - len2; ++i) {
            sum = num1[len1 - len2 - i - 1] - '0' + carry;

            if (sum >= 10) {
                carry = 1;
                num1[len1 - len2 - i - 1] = sum - 10 + '0';
            } else {
                carry = 0;
                num1[len1 - len2 - i - 1] = sum + '0';
            }

            if (carry == 0) {
                break;
            }
        }

        if (carry == 1) {
            char *num = (char *)malloc((len1 + 1 + 1) * sizeof(char));
            memcpy(num + 1, num1, len1 + 1);
            num[0] = '1';
            free(num1);
            *str1 = num;
        }
    }
}

同样地,我们也需要一个字符串逆序子程序,并且对于逆序后开头为 0 的数要将 0 去除。

char *reverse(const char* positive)
{
    int len;
    char *reverse_num;

    /* trim the zero(s) on the tail */
    for (int i = strlen(positive); i > 0; --i ) {
        if (positive[i - 1] != '0') {
            len = i;
            break;
        }
    }

    reverse_num = (char *)malloc((len + 1) * sizeof(char));
    reverse_num[len] = '\0';

    for (int i = 0; i < len; ++i) {
        reverse_num[i] = positive[len - i - 1];
    }

    return reverse_num;
}

主程序逻辑类似:

int main()
{
    char *num;
    char *reverse_num;
    int step = 0;

    num = (char *)malloc(1024 * sizeof(char));
    printf("Please input the number: ");
    gets(num);

    reverse_num = reverse(num);
    while (0 != strcmp(num, reverse_num)) {
        add(&num, &reverse_num);
        ++step;
        free(reverse_num);
        reverse_num = reverse(num);
    }
    free(reverse_num);

    printf("Find palindrome %s with %d step(s)\n", num, step);

    return 0;
}

这样我们就能测试任意大数了。

➜  Lychrel gcc -o test test.c
➜  Lychrel ./test
Please input the number: 1186060307891929990
Find palindrome 44562665878976437622437848976653870388884783662598425855963436955852489526638748888307835667984873422673467987856626544 with 261 step(s)
➜  Lychrel 

可以看到,程序运行符合预期。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会为你提供这些问题的C语言程序实现。 1. 删除重复字符 ```c #include <stdio.h> #include <string.h> void remove_duplicate_chars(char str[]) { int len = strlen(str); int i, j, k; for (i = 0; i < len; i++) { for (j = i + 1; j < len; j++) { if (str[j] == str[i]) { for (k = j; k < len; k++) { str[k] = str[k + 1]; } len--; j--; } } } } int main() { char str[100]; printf("请输入一个字符串:"); gets(str); remove_duplicate_chars(str); printf("删除重复字符后的字符串为:%s\n", str); return 0; } ``` 2. 回文数判断 ```c #include <stdio.h> #include <string.h> int is_palindrome(int num) { char str[10]; sprintf(str, "%d", num); int len = strlen(str); int i; for (i = 0; i < len / 2; i++) { if (str[i] != str[len - i - 1]) { return 0; } } return 1; } int main() { int num; printf("请输入一个整:"); scanf("%d", &num); if (is_palindrome(num)) { printf("%d是回文数\n", num); } else { printf("%d不是回文数\n", num); } return 0; } ``` 3. 单词统计 ```c #include <stdio.h> #include <string.h> int count_words(char str[]) { int len = strlen(str); int i, count = 0; for (i = 0; i < len; i++) { if (str[i] == ' ' || str[i] == '\n' || str[i] == '\t') { count++; } } return count + 1; } int main() { char str[1000]; printf("请输入一段文本:\n"); fgets(str, sizeof(str), stdin); int count = count_words(str); printf("单词为:%d\n", count); return 0; } ``` 4. 合法C标识符 ```c #include <stdio.h> #include <string.h> #include <ctype.h> int is_valid_identifier(char str[]) { int len = strlen(str); int i; if (!isalpha(str[0]) && str[0] != '_') { return 0; } for (i = 1; i < len; i++) { if (!isalnum(str[i]) && str[i] != '_') { return 0; } } return 1; } int main() { char str[100]; printf("请输入一个标识符:"); scanf("%s", str); if (is_valid_identifier(str)) { printf("%s是合法的C标识符\n", str); } else { printf("%s不是合法的C标识符\n", str); } return 0; } ``` 5. 奖学金 ```c #include <stdio.h> int main() { int n, i; double score, sum = 0, max = 0; scanf("%d", &n); for (i = 0; i < n; i++) { scanf("%lf", &score); sum += score; if (score > max) { max = score; } } double avg = sum / n; if (avg >= 80 && max >= 90) { printf("奖励1000元\n"); } else if (avg >= 80) { printf("奖励800元\n"); } else if (avg >= 60) { printf("奖励500元\n"); } else { printf("很遗憾,没有奖励\n"); } return 0; } ``` 6. 密码翻译 ```c #include <stdio.h> #include <string.h> #include <ctype.h> int main() { char str[100]; printf("请输入需要翻译的字符串:"); fgets(str, sizeof(str), stdin); int len = strlen(str); int i; for (i = 0; i < len; i++) { if (isalpha(str[i])) { if (isupper(str[i])) { str[i] = 'A' + ('Z' - str[i]); } else { str[i] = 'a' + ('z' - str[i]); } } } printf("翻译后的字符串为:%s\n", str); return 0; } ``` 希望这些程序能够帮助到你,如果有任何问题欢迎提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值