• 求回文数算法


    问题:

        求第N个回文数palindrome。

        一个正数如果顺着和反过来都是一样的(如13431,反过来也是13431),就称为回文数。约束:

        回文数不能以0开头

        回文数从1开始。

    首先我们要写一个算法求回文数。刚开始我想到用用字符串来存储数,然后判断原序和逆序是否相等。

    void func1(char a[])
    {
        printf("%d",strlen(a));
     
        char *p=a;
            char *q=a+strlen(a)-1;  
            bool flag=true;
            while(q>p)
            {
                if(*q!=*p)
                {
                    flag=false;
                    break;
                }
                q--;p++;
            }
            if(flag)
                printf("%s 是回文数
    ",a);
            else
                printf("%s 不是回文数
    ",a);
             
    
    }
    int main()
    {
         
        char s[50];
        while(scanf("%s",s)!=0)
        {
          printf("%d",strlen(s));
           func1(s);
             
        }

    注意,用strlen的时候只检测什么时候到‘'位置,与sizeof无关,如果是sizeof的话char a[]做函数参数a会降级为指针

    虽然这样做可以,但还是有点小问题,如果输入010,输出回文。不满足回文的定义。

    回文数不能以0开头

      一开始就思考使用循环:从1开始,判断该数是否是回文数,然后用一

    个计数器记下回文数,一直到计数器得到N,返回第N个回文数。比较常用的是以下这种方法来判断是

    否回文数:

    static boolean isPN(int num) {
        int o = num;
        int tmp = 0;
        //使用循环把数字顺序反转
        while(num != 0) {
            tmp *= 10;
            tmp += num % 10;
            num /= 10;
        }
        //如果原始数与反转后的数相等则返回true
        if(tmp == o) 
            return true;
        return false;
    }

    这种思路的确可得到正确结果,但随着用来测试的N的增大,效率的问题就浮现了。因为是一重

    循环,效率是O(n)。所以当N非常大时,所花的时间还是十分大的。

    另一种思路:

        回文数的个数其实是有规律的。如:

        1位回文数: 9个

        2位回文数: 9个

        3位回文数: 90个

        4位回文数: 90个

        5位回文数: 900个

        6位回文数: 900个

        …

        我们看到9、90、900,是不是很有规律,那是什么原因?很简单,我们把回文数拆开两半

    [123321]来看。两半的变化一样的,那我们只算其中一半就行了。首位不能是0,所以左半最小为

    100,最大为999,共有999-100+1=900个,如此类推。

        所以我们可以基于以下原则:

        1、 回文数的数位每增长2,回文数的个数为原来的10倍。如从个位回文数到百位回文数,个数

    从9个变为90个。

        2、 个位回文数的个数是9,1、2、3、…、9。

        总之理解原理后一切好办,步骤就偷懒不写了,看代码吧!

    核心代码:

    static long find(int index) {
            int count = 0;            
            int number = 9;                        //记录数位上的回文数,如个位回文数为9
            int w = 0;                            //记录数位
            
            long half;                            //保存回文数的左半边的结果
            long h = 1;                            //回文数的左半边的起始基数
            long res;                            //结果
            
            while(true) {
                if(w > 0 && w%2 == 0) {            //每进两个数位,回文数乘以10
                    number *= 10;
                }
                w++;                            //数位加一
                if(count + number > index)        //回文数大于查找的回数,跳出
                    break;
                    
                count += number;                //回文数加上当前数位上的回文数
            }
            
            index -= count;                        //在当前数位上的位置。如w=5,index=50,则万位上的第50个回文数是我们所求
            
            for(int i = 0; i < (w-1) / 2; i++) {    //求回文数的左半边的基数,如回文数在万位上,则为100
                h *= 10;
            }
            
            half = h + index;                        //回文数的左半边,如100 + 50 = 150
            
            res = half;
            
            if(w%2 != 0)                            //如果为奇数,则中间那个数不必算入右半边了!
                half /=10;
                
            while(half != 0) {                        //拼接回文数
                res = res *10 + half % 10;
                half /= 10;
            }
            
            return res;
        }

    全部代码:

    package com.icescut.classic.algorithm;
    //数位指个位,十位,百位,千位。。。
    class PalindromicNumber {
        public static void main(String[] args) {
            int input = Integer.parseInt(args[0]);
            long res = find(input);
            System.out.println("res:" + res);
            
        }
        
        static long find(int index) {
            int count = 0;            
            int number = 9;                        //记录数位上的回文数,如个位回文数为9
            int w = 0;                            //记录数位
            
            long half;                            //保存回文数的左半边的结果
            long h = 1;                            //回文数的左半边的起始基数
            long res;                            //结果
            
            while(true) {
                if(w > 0 && w%2 == 0) {            //每进两个数位,回文数乘以10
                    number *= 10;
                }
                w++;                            //数位加一
                if(count + number > index)        //回文数大于查找的回数,跳出
                    break;
                    
                count += number;                //回文数加上当前数位上的回文数
            }
            
            index -= count;                        //在当前数位上的位置。如w=5,index=50,则万位上的第50个回文数是我们所求
            
            for(int i = 0; i < (w-1) / 2; i++) {    //求回文数的左半边的基数,如回文数在万位上,则为100
                h *= 10;
            }
            
            half = h + index;                        //回文数的左半边,如100 + 50 = 150
            
            res = half;
            
            if(w%2 != 0)                            //如果为奇数,则中间那个数不必算入右半边了!
                half /=10;
                
            while(half != 0) {                        //拼接回文数
                res = res *10 + half % 10;
                half /= 10;
            }
            
            return res;
        }
    }

    说明:

        因为按规律计算,效率为O1,不论数量级多大,能马上得到结果(不发生溢出情况下)。对比循环判断回文数的方法,大大的改善了。

    转自:http://www.cnblogs.com/icescut/archive/2009/11/09/PalindromicNumber.html

    缺8数、回文数的秘密

     人们把12345679叫做“缺8数”,这“缺8数”有许多让人惊讶的特点,比如用9的倍数与它相乘,乘积竟会是由同一个数组成,人们把这叫做“清一色”。比如:

     

    12345679*9=111111111

    12345679*18=222222222

    12345679*27=333333333

    ……

    12345679*81=999999999

    这些都是9的1倍至9的9倍的。

    还有99、108、117至171。最后,得出的答案是:

    12345679*99=1222222221

    12345679*108=1333333332

    12345679*117=1444444443

     。。。

    12345679*171=2111111109

     

    回文数

    中文里,有回文诗句、对联,如:"灵山大佛,佛大山灵","客上天然居,居然天上客"等等,都是美妙的符合正念倒念都一样的回文句.

    回文数则是有类似22、383、5445、12321,不论是从左向右顺读,还是从右向左倒读,结果都是一样的特征.许多数学家着迷于此。

    回文数中存在无穷多个素数11,101,131,151,191……。除了11以外,所有回文素数的位数都是奇数。道理很简单:如果一个回文素数的位数是偶数,则它的奇数位上的数字和与偶数位上的数字和必然相等;根据数的整除性理论,容易判断这样的数肯定能被11整除,所以它就不可能是素数。附整除原理11整除的特征。

    能被11整除的数的特征
    把一个数由右边向左边数,将奇位上的数字与偶位上的数字分别加起来,再求它们的差,如果这个差是11的倍数(包括0),那么,原来这个数就一定能被11整除.
    例如:判断491678能不能被11整除.
    —→奇位数字的和9+6+8=23

    —→偶位数位的和4+1+7=12 23-12=11
    因此,491678能被11整除.
    这种方法叫"奇偶位差法".
    除上述方法外,还可以用割减法进行判断.即:从一个数里减去11的10倍,20倍,30倍……到余下一个100以内的数为止.如果余数能被11整除,那么,原来这个数就一定能被11整除.
    又如:判断583能不能被11整除.
    用583减去11的50倍(583-11×50=33)余数是33, 33能被11整除,583也一定能被11整除.

     

     )。

    人们借助电子计算机发现,在完全平方数、完全立方数中的回文数,其比例要比一般自然数中回文数所占的比例大得多。例如11^2=121,22^2=484,7^3=343,11^3=1331……都是回文数。

    人们迄今未能找到四次方、五次方,以及更高次幂的回文素数。于是数学家们猜想:不存在nk(k≥4;n、k均是自然数)形式的回文数。

     

    在电子计算器的实践中,还发现了一桩趣事:任何一个自然数与它的倒序数相加,所得的和再与和的倒序数相加,……如此反复进行下去,经过有限次步骤后,最后必定能得到一个回文数

  • 相关阅读:
    tornado之运行第一个tornado程序
    Django之QuerySet 查询
    openstack之路:KVM/Libvirt 安装
    【原创】Linux基础之SSH隧道/端口转发
    【原创】运维基础之keepalived
    【原创】数据库基础之Mysql(2)主从库配置
    【原创】Linux基础之iptables
    【原创】大叔经验分享(28)ELK分析nginx日志
    【原创】算法基础之Anaconda(1)简介、安装、使用
    【原创】大数据基础之Airflow(1)简介、安装、使用
  • 原文地址:https://www.cnblogs.com/youxin/p/3234785.html
Copyright © 2020-2023  润新知