最近回文数
描述:
给定一个整数 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转化成字符串的时候,结果更令人’欣慰‘ ,还有个坑是当两边为字符串时的比较大小 好像是比较他们的字典顺序的。