Palindrome Number

https://oj.leetcode.com/problems/palindrome-number/

Determine whether an integer is a palindrome. Do this without extra space.

click to show spoilers.

Some hints:

Could negative integers be palindromes? (ie, -1)

If you are thinking of converting the integer to string, note the restriction of using extra space.

You could also try reversing an integer. However, if you have solved the problem "Reverse Integer", you know that the reversed integer might overflow. How would you handle such case?

There is a more generic way of solving this problem.

解题思路:

首先注意,负数不是回文数。

开始想到将一个数字分为两半,例如123454321,前后两半加起来的和,每位都相等,那么这个数就是一个回文数。当然,这里要考虑位数的奇偶。后来证明这么考虑是错误的,简单的,1122就不是回文数。而且,这么做还要考虑123这样的情况,分为两半后,相加只有一位,只能直接判断两者是否相等。这里还是提供以下代码。

public class Solution {

    public boolean isPalindrome(int x) {

        //重要

        if(x < 0){

            return false;

        }

        // x = Math.abs(x);

        if(x < 10){

            return true;

        }

        

        int digit = 1;

        int temp = x / 10;

        while(temp > 0){

            temp = temp / 10;

            digit++;

        }

        

        if(digit % 2 == 0){

            //前半截的数值

            int highHalf = x;

            for(int i = 0; i < digit / 2; i++){

                highHalf = highHalf / 10;

            }

            int lowHalf = x - highHalf * (int)Math.pow(10, digit / 2);

            int sumHalf = highHalf + lowHalf;

            //注意sumHalf只有一位的情况

            if(lowHalf < 10 && highHalf < 10){

                return lowHalf == highHalf;

            }

            int divide = sumHalf % 10;

            sumHalf = sumHalf / 10;

            while(sumHalf > 0){

                if(divide != sumHalf % 10){

                    return false;

                }

                sumHalf = sumHalf / 10;

            }

        }else if(digit % 2 != 0){

            int highHalf = x;

            for(int i = 0; i < digit / 2; i++){

                highHalf = highHalf / 10;

            }

            int mid = highHalf % 10;

            highHalf = highHalf / 10;

            int lowHalf = x - highHalf * (int)Math.pow(10, digit / 2 + 1) - mid * (int)Math.pow(10, digit / 2);

            if(lowHalf < 10 && highHalf < 10){

                return lowHalf == highHalf;

            }

            int sumHalf = highHalf + lowHalf;

            int divide = sumHalf % 10;

            sumHalf = sumHalf / 10;

            while(sumHalf > 0){

                if(divide != sumHalf % 10){

                    return false;

                }

                sumHalf = sumHalf / 10;

            }

        }

        return true;

    }

}

 想到回文数的定义,其实是一个递归的定义。

如果n<0,那么不是回文数。

如果0<=n<10,n为回文数。

如果9<n<100,两位数字相等,n为回文数。

如果n>99,n的首尾数字相等,并且去掉这两个数子,n仍然是回文数,那么n就是一个回文数。

代码如下:

public class Solution {

    public boolean isPalindrome(int x) {

        //重要

        if(x < 0){

            return false;

        }

        

        if(x < 10){

            return true;

        }

        

        if(x < 100){

            return x / 10 == x % 10;

        }

        

        int digit = 1;

        int high = x / 10;

        while(high >= 10){

            high = high / 10;

            digit++;

        }

        digit++;

        

        int low = x % 10;

        int x_remove_high_and_low = (x - high * (int)Math.pow(10, digit - 1)) / 10;

        

        return high == low && isPalindrome(x_remove_high_and_low);

    }

}

可是,这个递归的算法无法处理1000021这样的数字。程序认为去掉首位后,2为回文,其实该数字不是回文数。

正确的解法很简单,把数字reverse,如果与原数字还相等,就是回文。这里考虑一下reverse后int溢出的问题,如果溢出,肯定不是回文了。前面reverse integer的问题讨论过溢出的处理方法。一种是直接用long存储reverse后的int来避免,第二种,就要讨论该数字是不是大于MAX_VALUE/10,或者已经==MAX_VALUE/10,而且最后一位大于MANX_VALUE的最后一位。下面就用简单的long的方法来做。

public class Solution {

    public boolean isPalindrome(int x) {

        //重要

        if(x < 0){

            return false;

        }

        // x = Math.abs(x);

        if(x < 10){

            return true;

        }

        

        long reverse = 0;

        int temp = x;

        while(temp > 0){

            reverse = reverse * 10 + temp % 10;

            temp = temp / 10;

        }

        

        return reverse == x;

    }

}

 原题提到了一直更为generic的方法,就是比较头尾两个数字,然后删掉,再比较。这个思路和前面判断回文字符串的思路类似。这里需要注意的有几点,首先必须借助一个类似于1000这样的数字,然后和x不断变小,用来取最高位。其次是要注意100021这样的数字,程序里注释写的比较清楚。去除首尾后,就变成了0002,计算机认为是2,就认为是回文数了,其实不是。

public class Solution {

    public boolean isPalindrome(int x) {

        //重要

        if(x < 0){

            return false;

        }



        if(x < 10){

            return true;

        }

        

        int tens = 1;

        int temp = x;

        

        //初始化一个tens,比如x=54321,tens=10000

        while(temp >= 10){

            tens = tens * 10;

            temp = temp / 10;

        }

        

        temp = x;

        //这里的判断条件必须是tens>=10,如果用temp,1000021这样的数字会出问题

        while(tens >= 10){

            int low = temp % 10;

            int high = temp / tens;

            if(low != high){

                return false;

            }

            //首尾都删去,tens就要少两位

            tens = tens / 100;

            //x删除首尾两位

            temp = temp / 10 - high * tens * 10;

        }

        return true;

    }

}

 

你可能感兴趣的:(number)