最近回文数

描述:

给定一个整数 n ,你需要找到与它最近的回文数(不包括自身)。

“最近的”定义为两个整数差的绝对值最小。

代码:

/**
 * @param {string} n
 * @return {string}
 */
var nearestPalindromic = function(n) {
    n = parseInt(n);
    function findPalindromic(num){
        let reverseNum = 0,origin = num;
        while( num ){
            reverseNum = reverseNum * 10 + num % 10;
            num =  Math.floor(num / 10);
        }
        
        if( origin == reverseNum )
            return origin.toString();
        return false;
    }
    
    let leftCount = 0,rightCount = 0; 
    while(true){
        let left  = findPalindromic( n + (--leftCount) );
        
        if(left)
            return left;
        
        let right = findPalindromic( n + (++rightCount) );
        
       
        if(right)
            return right
    }
    
};

思路: 没错,一开始就想到的是枚举,暴力寻找数据----老实人的算法 哈哈哈,然后我现在要换思路了,打算从给出的数据中找规律;

嗯 一会儿看看能不能找出

20180914 10.15

代码:

/**
 * @param {string} n
 * @return {string}
 */
var nearestPalindromic = function(n) {
//     n = parseInt(n);
    function findPalindromic(num){
        let reverseNum = 0,origin = num;
        while( num ){
            reverseNum = reverseNum * 10 + num % 10;
            num =  Math.floor(num / 10);
        }
        
        if( origin == reverseNum )
            return origin.toString();
        return false;
    }
    
   
    
        
        
        if(n.length == 1) return (--n).toString() +'';
        if( n.length > (--n).toString().length ){
            return n+'';
        }
        n = (++n).toString();
    
        if( findPalindromic(n) ){
             n = +n;
             let leftCount = 0,rightCount = 0; 
                while(true){
                    let left  = findPalindromic( n + (--leftCount) );

                    if(left)
                        return left;

                    let right = findPalindromic( n + (++rightCount) );


                    if(right)
                        return right
                }
        }
        let mid = Math.floor(n.length / 2),
            left= n.slice(0,mid),

            right = n.length % 2 == 0 ? n.slice( mid ) : n.slice(mid + 1),
            leftDiff = left - right.split('').reverse().join(''),
            rightDiff = right - left.split('').reverse().join('');

            if( n.length % 2 == 0 ){
              if( Math.abs( +(parseInt( left ) - leftDiff + right) - n ) >  Math.abs( +( left  + ( parseInt(right) - rightDiff )) - n)){
                  return ( left  + ( parseInt(right) - rightDiff ));
              }else{
                  return ((parseInt( left ) - leftDiff + right) > ( left  + ( parseInt(right) - rightDiff )) ) ? ( left  + ( parseInt(right) - rightDiff )): (parseInt( left ) - leftDiff + right);
              }
            }else{
                if( Math.abs( +(parseInt( left ) - leftDiff + right) - n ) >  Math.abs( +( left  + ( parseInt(right) - rightDiff )) - n)){
                  return ( left  + n[mid] + ( parseInt(right) - rightDiff ));
                }else{
                  return ( (parseInt( left ) - leftDiff + n[mid] + right) > ( left  + n[mid] + ( parseInt(right) - rightDiff )) )? ( left  + n[mid] + ( parseInt(right) - rightDiff )) : (parseInt( left ) - leftDiff + n[mid] + right);
                }
            }
    
};

思路:

就是说,一个数要想变成回文数, 可以把他分成两半儿,要么让左边的变成右边相反的部分,要么反之,然而测试用例很快就打了我的脸,这样找出来的回文数不是最近的 /再见。。。
然后是找了一圈儿解答,自己摸索着的写法:

/**
 * @param {string} n
 * @return {string}
 */
var nearestPalindromic = function(n) {
    

     // 返回反序字符串 eg. 123 =》 321
    function findMirror(num){       
        return  num.split('').reverse().join('') ;
    }
    
   // 用了一些二进制算法,为了骚, l>>1 就是 l / 2 ,然后 l & 1 是为了区分l是奇数还是偶数
    let result = new Map(),
        l = n.length,
        mid = l >> 1,
        left = n.slice(0,mid + (l & 1));
    
    if( l == 1)
        return (--n).toString();
    
    // palindrome 比原来长度小一位的最大回文数  和 比原来长度大一位的最大回文数
    // 这个主要是找出当所给数字在 100 , 或者 99 这种容易使数字长度发生变化的时候找出对应的数字
    let less='',more='';
    for( let i = 0; i < l-1; i++)
        less += '9';
    for( let i = 0; i <= l; i++ ){
        if( i==0 || i== (l))
            more += '1'
        else
            more += '0'
    }
    result.set( 'key1', less  );
    
    
    result.set( 'key2', more );
    /**
     * 这是核心思想,和我初始时的想法差不多,不过我们为了取绝对值比较小的区间
     * 直接使用左半边的替换右半边的就行了,当长度为奇数时,最中间的一位不能复制两次
     *  所以用了 l & 1 ,当为奇数时 结果为 slice( 0, length - 1);
     *  然后就是我没有想到的东西:
     * 当我们截取的左半边也会越位,即 末尾为 0 或 9 时  因为当他们 - 1 或 +1 
     *  时也会使结果发生变化
     * 所以我们  要讨论的就是 使 左半边 +1, +0(代表原来的数),-1 三种情况分别产生的回文数
     * 然后比较结果 就ok啦
     */
    for( let i = -1 ; i <=1; i++){
        
        if( (+left) + i + '' + findMirror( ((+left) + i).toString().slice(0, left.length == 1 ? 1: left.length - (l & 1)  )) == n ) 
            continue;
        
        result.set( i, (+left) + i + '' + findMirror( ((+left) + i ).toString().slice(0, left.length == 1 ? 1:left.length - (l & 1))  ) );
        
    }
    
    let minum , abs = Infinity;
    console.log(result);
    for( let value of result.values()){
        if( Math.abs( value - n ) < abs ){
            minum = value;
            abs = Math.abs( value - n );
        }
        if( Math.abs( value - n ) == abs ){
            minum = +minum > value ? value : minum;
        }
        console.log(minum)
    }
    return minum;
};

最后值得一提的是,js坑爹的数字运算,Math.pow( 10 ,17) -1 = 100000...000,根本不会产生999...999所以才是用了for拼接字符串的方式来生成less和more,真的坑,然后 Math.min 会产生一个数值,当这个数值使用toString转化成字符串的时候,结果更令人’欣慰‘ ,还有个坑是当两边为字符串时的比较大小 好像是比较他们的字典顺序的。

posted @ 2018-09-15 20:44  子龙_子龙  阅读(11)  评论(0编辑  收藏  举报