1.题目
如标题,求大于整数N(N>=0)的第一个回文数的字符串表示形式。
这个题目也是当时笔试第一次见到,花了一个小时才做出了。慢慢总结还是挺简单的。
2.分析
分析如下:
(1)一位数N(9除外)。
第一个大于N回文数等于N+1,如大于3的第一个回文数是4。
(2)奇数位(一位数除外)
需要看“左边反转数字”是否大于"右边数字"。
1)如果小于等于,则“左边+中间字母”组成的数字+1,再对称就可以。
2)如果大于,则左边数字直接对称到右边就可以啦。
(3)偶数位
需要看“左边反转数字”是否大于"右边数字"。
1)如果小于等于,则“左边”组成的数字+1,再对称就可以。
2)如果大于,则左边数字直接对称到右边就可以啦。
(4)特殊情况(其实就一种)
1)N=9,大于N的下一个回文数是11,即N+2
2)奇数情况(位数!=1)。
N1=99900,右边数字小于“左边,翻转数字”,直接对称,所以大于N1的第一个回文数是99999。(满足上面的讨论规则)
N2=99999,右边数组大于等于“左边,翻转数字”,使用上面的讨论规则结果为1000 001 ,不正确。结果应该是N2+2
3)偶数情况。
N1=9900,右边数字小于“左边翻转数字”,直接对称,所以大于N1的第一个回文数是9999。(满足上面的讨论规则)
N2=9999,右边数组大于等于“左边翻转数字”,使用上面的讨论规则结果为100 001 ,不正确。结果应该是N2+2
所以,可以将特殊情况归结为一种,当整数N满足正则表达式"9+"时,大于N的第一个回文数是N+2。(9,99,999,9999,.....)
3.生成代码+测试代码
/**
* 生成函数:
* firstBiggerPalindrome(String n)
* isLeftReverseBiggerRight(String left, String right)
* 后期使用for循环校验N in [0,1000000)时的情况函数:
* nextPalindromeUseFor(int num, boolean[] Palindrome)
* isPalindrome(int num)
*
* 在main函数内进行算法生成 与 for循环暴力生成的校验
* */
public class Solution {
static String firstBiggerPalindrome(String n) { // 生成大于整数N(字符串表示)的第一个回文整数
n = String.valueOf(Integer.parseInt(n)); // 避免前导符"0",如n="009"
if (n.matches("9+")) // 特殊情况直接处理
return String.valueOf(Integer.parseInt(n) + 2);
int len = n.length();
if (len == 1) // 长度为1
return String.valueOf(Integer.parseInt(n) + 1);
StringBuilder left = new StringBuilder(); // 左边
StringBuilder right = new StringBuilder(); // 右边
StringBuilder res = new StringBuilder(); // 结果
if ((len & 0x1) == 1) { // 奇数位
left.append(n.substring(0, len >> 1));
right.append(n.substring((len >> 1) + 1));
if (isLeftReverseBiggerRight(left.toString(), right.toString())) { // 如果左边翻转数字大于右边,直接翻转
res.append(left);
res.append(n.charAt(len >> 1));
res.append(left.reverse().toString());
} else { // 否则,“左边+中间”数字加1,再翻转
left.append(n.charAt(len >> 1));
int num = Integer.parseInt(left.toString()) + 1;
left.setLength(0);
left.append(num);
res.append(num);
res.append(left.deleteCharAt(left.length() - 1).reverse()
.toString());
}
} else { // 偶数为
left.append(n.substring(0, len >> 1));
right.append(n.substring(len >> 1));
if (!isLeftReverseBiggerRight(left.toString(), right.toString())) {
int num = Integer.parseInt(left.toString()) + 1;
left.setLength(0);
left.append(num);
}
res.append(left.toString());
res.append(left.reverse().toString());
}
return res.toString();
}
static boolean isLeftReverseBiggerRight(String left, String right) { // 比较左边翻转后数字与右边数字的大小关系
StringBuilder sb = new StringBuilder(left);
if (sb.reverse().toString().compareTo(right) > 0)
return true;
return false;
}
static String nextPalindromeUseFor(int num, boolean[] Palindrome) { // 求大于num的第一个回文数(最后的测试代码使用)
for (int i = num + 1; i < Palindrome.length; i++) {
if (Palindrome[i] == true)
return String.valueOf(i);
}
return null;
}
static boolean isPalindrome(int num) { // 判断一个数字是不是回文数字(最后的测试代码使用)
String str = String.valueOf(num);
int i = 0;
int j = str.length() - 1;
while (i < j) {
if (str.charAt(i) != str.charAt(j))
return false;
i++;
j--;
}
return true;
}
public static void main(String[] args) throws IOException {
int n = 1000000; // 只测试[0,1000000)以内的结果
boolean[] Palindrome = new boolean[n]; //默认为false
for (int i = 0; i < n; i++) {
if (isPalindrome(i))
Palindrome[i] = true; //如果是回文数字,标记为true。编译下一步校验,大于N的第一个回文数字
}
for (int i = 0; i < n; i++) {
String val = firstBiggerPalindrome(String.valueOf(i)); //程序生成
if (Integer.parseInt(val) < n) { //如果在[0,1000000)内,进行校验
if (!val.equals(nextPalindromeUseFor(i, Palindrome)))
System.out.println("BAD\t" + i);
}
}
}
}