【C语言】好题分享——回文对称数

文章目录

  • 1️⃣题目
  • 2️⃣解题思路
    • 1.总体逻辑
    • 2. 核心部分
      • (i) 暴力求解 (比较法)
      • (ii) 计算回文数 1.0
      • (iii) 计算回文数 2.0


1️⃣题目

今天想给大家分享一道来自牛客网上的题目,感觉其中的思路很是巧妙,题目是这样子的。
描述
今天牛牛学到了回文串,他想在数字里面找回文,即回文数,回文数是正着读与倒着读都一样的数,比如1221,343是回文数,433不是回文数。请输出不超过n的回文数。
输入描述:
输入一个整数n(1 <= n <= 100000)
输出描述:
从1开始按从小到大的顺序输出所有回文数




2️⃣解题思路

1.总体逻辑

想要找出1到n中所有的回文数并按顺序输出,这个逻辑并不难实现,只需要利用for循环从1到n遍历,找到回文数就输出,不是回文数就不输出即可。

总体代码如下⭕

int main()
{
    int n = 0;
    scanf("%d", &n);
    int i = 0;
    for (i = 1;i <= n;i++)
    {
        if (reverse_is_same(i))
        {
            printf("%d\n", i);
        }
    }
    return 0;
}

这里面的重点是reverse_is_same函数(判断该数是否为回文对称数)的实现,下面就让我们来看看它是如何实现的吧!!




2. 核心部分

(i) 暴力求解 (比较法)

刚开始看到这题时,我就在想,判断一个数字是否为回文对称数就是该数左右对称的两个数一一相等,那么,怎么样能一对一对地比较一个数字中左右对称的两个数呢?我们知道,如果是我们想比较的不是一个整数而是一个数组,那就变得简单了。我们可以通过数组下标的访问,同时访问左右对称的两个数,并将二者进行比较,逐一进行比较后每一对都相同即为回文对称数。那么这道题就有了第一种思路,将该数转换为数组进行求解,这种方法比较暴力,但是不难想出来!

具体代码如下⭕

#include 
int reverse_is_same(int i)
{
    int n=1;
    int tmp=i;
    while(tmp/=10)//求出该数的位数以确定数组长度
    {
        n++;
    }

    int arr[100] = {0};//在C99标准中,可直接定义变长数组arr[n]
    int j=0;
    for(j=n-1;j>=0;j--)//取出每一位,将各位数放到数组中(从后向前放)
    {
        arr[j] = i%10;
        i/=10;
    }
    int left=0;//数组最左边的下标(可认为访问整数i的第一位)
    int right=n-1;//数组最右边的下标(可认为访问整数i的最后一位)
    while(left<right)//循环条件设置为left
    {
        if(arr[left]==arr[right])
        {
            left++;//左右下标逐渐靠近
            right--;
        }
        else
            return 0;//只要有一对不相等便直接返回0,为假
    }
    return 1;//每一对都相等,既返回1,为真
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    int i = 0;
    for (i = 1;i <= n;i++)
    {
        if (reverse_is_same(i))
        {
            printf("%d\n", i);
        }
    }
    return 0;
}

这里面求出 i 的位数尤为重要。我们先将 i 的值存进临时变量tmp中,用tmp进行求位数的操作(因为后面还需用到 i ,此操作为可能改变 i 的值)。我们知道,一个整数至少有一位数,因此定义n=1,默认tmp有一位数,接下来利用while循环,让tmp/=10复合赋值,如果复合赋值的结果不等于0,进入循环,位数n加一,等于0则跳出循环,此时n便为tmp(也就是i)的位数。
这里的取出一个整数的各位数也是关键所在,它是实现方式是这样子的。将一个数字%10,便得到它的最后一位,得到最后一位后再将其复合赋值/=10,便将原来的最后一位去掉了,那么他此时的最后一位就是原来的倒数第二位,又可以通过该方法求出此时的最后一位。依次类推,直到整数的值为0为止,便可取出每一位。(如:123%10=3,123/=10–>12;12%10=2,12/=10–>1;1%10=1,1/=10–>0)。在此我称这种方法为%10/10法。




(ii) 计算回文数 1.0

上面是将数字转化为数组并逐对进行比较。那么,我们是否能直接求出整数的回文数,再看它是否为回文对称数呢?(既与原数进行比较,相同则为回文对称数)答案是可以的。我们可以取整数 i 的每一位,并将其乘10的n次方(视 i 的位数而定,最低位乘最高次方),再将每一位乘的n次方相加起来,便可得到回文数。

具体代码如下⭕

#include 
#include 
int reverse_is_same(int i)//算出回文数(比较容易的理解)
{
    int n=1;
    int tmp=i;//用临时变量tmp替代i,尽量不要改变i的值
    while(tmp/=10)//算出i的位数n
    {
        n++;
    }

    tmp = i;//注意此时tmp的值已经改变,重新给其赋值i
    int j=0;
    int ri=0;//ri为回文数
    for(j=n-1;j>=0;j--)//计算回文数
    {
        ri+=((tmp%10)*pow(10,j));
        tmp/=10;
    }

    return ri == i;//返回表达式的值(表达式为真返回1,为假返回0)
}

这里求回文数的思路如下:
【C语言】好题分享——回文对称数_第1张图片

以整数123为例,已知123的位数为3,则我们取123的每一位,最低位3乘10^2,倒数第二位乘10^2,以此类推,将每次的计算结果累加起来即可得到回文数ri。
推广到所有整数,既从最低位到最低位取出每一位(利用%10再/10),最低位乘10^n-1,倒数第二位乘10^n-2,依次类推,最高位乘10的0次方(既1),再将每次的计算结果累加起来即可得到回文数ri。




(iii) 计算回文数 2.0

下面分享一种秒解,同样是求出回文数,但其思路比第一种求回文数的方法巧妙了许多,下面直接上代码分析。

具体代码如下⭕

#include 
int reverse_is_same(int i)
{
    int ri = 0;
    int tmp = i;
    while (tmp)
    {
        ri = ri * 10 + (tmp % 10);
        tmp /= 10;
    }
    return ri == i;
}

可以看到,这里并不用求出 i 的位数,便直接进行求回文数的操作。这里我理解的是将低位逐渐向前推移,最低位推到最高位,倒数第二位推到第二位,以此类推。在循环中,依然是通过%10/10这个原理取出每一位,最后一位取出来后,在下次循环中乘10加上倒数第二位,便交换了后两个数,依次类推即可完成计算回文数。

通过画图更好地理解⭕

【C语言】好题分享——回文对称数_第2张图片


本次分享到此就结束啦!!如果本文对你有些许的帮助,不妨给作者一个一键三连吧!!如有错误,欢迎大佬指正!

你可能感兴趣的:(刷题记录,c语言,算法)