564. 寻找最近的回文数
题目描述:
给定一个整数 n ,你需要找到与它最近的回文数(不包括自身)。
“最近的”定义为两个整数差的绝对值最小。
示例 1:
输入: “123”
输出: “121”
注意:
- n 是由字符串表示的正整数,其长度不超过18。
- 如果有多个结果,返回最小的那个。
题目难度:
题目思路:
1、要求一个数的回文,首先想到的是将这个数的末尾数字变成首位,其他位置依次进行。
本题也是采用这个思路。但是这种方法计算出来的结果不一定是最优解。因此本题还采用了求比这个数大的回文数和比这个数小的回文数。
2、根据步骤一:根据给定得值,然后再根据位置变换能求出一个对应的回文数。(如1299则变换之后为1221,此处不是最优解)。即最后一位等于第一位,chs[len - 1 - i] = chs[i]。
3、根据步骤二:如果求出的变换值比当前值大,则需要再求出比当前值小的回文数是多少。
求比给定值小的回文数:(如12345,则从3所在位置位置减1,然后根据步骤一求对应回文)
- 如果长度为奇数,就从中间位置变换,如果是偶数,就从前半位置变换;
- 如果当前位置为0,则变为9,同时前一位置减1;
- 如果变完之后,首位为0,则最终值的长度,在给定值长度基础减1,并所以位置全部变为9即可(如1001,按上面减法,则变为了,0901;因此要变为999);
- 如果给定值的长度为1,则最小回文直接为0即可。
最后再用位置变换,求出小值回文。
4、根据步骤二:如果求出比当前值小,则需要找到比给定值大的回文。
求比给定值大的回文数:为了防止,第一位出现9相加之和回文长度变化的情况(如999变为1001后,长度由3变为4)。因此要申请一个长度加1的数组空间。从(size - 1) / 2+1位置开始,加1,
- 如果长度为奇数,就从中间位置变换,如果是偶数,就从前半位置变换;
- 如果遇到9的情况,当前位置变0,并向前一位加1操作。
- 最后,判断第一位为1还是0,然后进行回文转换,求出大值回文数。
5、综合以上步骤:big - num >= num - small ? small : big,求出最优解。
代码实现:
/**
* Created by Zhaoyang Ge on 2018/9/7.
*/
public static String nearestPalindromic(String n) {
Long num = Long.valueOf(n); //把字符串转为long进行大小比较
Long raw = getRawPalindrome(n);
Long big = raw <= num ? getBigPalindrome(num) : raw;
Long small = raw < num ? raw : getSmallestPalindrome(num);
return String.valueOf(big - num >= num - small ? small : big);
}
private static Long getRawPalindrome(String n) {
char[] chs = n.toCharArray();
for (int i = 0; i < chs.length / 2; i++) {
chs[chs.length - 1 - i] = chs[i];
}
return Long.valueOf(String.valueOf(chs));
}
private static Long getSmallestPalindrome(Long raw) {
char[] chs = String.valueOf(raw).toCharArray();
char[] res = new char[chs.length];
int size = res.length;
for (int i = 0; i < chs.length; i++) {
res[i] = chs[i];
}
for (int i = (size - 1) / 2; i >= 0; i--) {
if (--res[i] < '0') {
res[i] = '9';
} else {
break;
}
}
if (res[0] == '0') {
res = new char[size - 1];
for (int i = 0; i < res.length; i++) {
res[i] = '9';
}
return size == 1 ? 0 : Long.valueOf(String.valueOf(res));
}
for (int k = size - 1; k > (size - 1) / 2; k--) {
res[k] = res[size - k - 1];
}
return Long.valueOf(String.valueOf(chs));
}
private static Long getBigPalindrome(Long raw) {
char[] chs = String.valueOf(raw).toCharArray();
char[] res = new char[chs.length + 1];
res[0] = '0';
for (int i = 0; i < chs.length; i++) {
res[i + 1] = chs[i];
}
int size = chs.length;
for (int i = (size - 1) / 2 + 1; i >= 0; i--) {
if (++res[i] > '9') {
res[i] = '0';
} else {
break;
}
}
int offset = res[0] == '1' ? 1 : 0;
size = res.length;
for (int i = size - 1; i >= (size + offset) / 2; i--) {
res[i] = res[size - i - offset];
}
return Long.valueOf(String.valueOf(res));
}