这道题答案其实只有70个最多,所以最快的解题者只要10ms(取巧);
我是用正常人能理解的思路进行解题
例如:2839-38456739538(随手写的两个数字)
先进行开方处理得到53-196103
附:我先定义"回文源",就是通过这个数可以得到回文数,加上boolean值可以获得回文,boolean用了区分是否重复最后一位,如(45,false)->454,(374,true)->374473;
得到回文源5,true-196true
判断6,true->9,true之间是否有超级回文源
判断10,false-999,false之间是否有超级回文源
判断100,true - 195,true之间是否有超级回文源
单独判断5,true和196true(不仅判断是否超级回文源,还要判断得到的数是否在区间内)
附:回文源的进阶是:10,false->99,false->10,true->99,true->100,false
虽然范围是在1018内,但是开方之后就是109,回文源就是105,运算时间是可以控制的
代码:
package month6;
public class Test906 {
public static void main(String[] args) {
System.out.println(new Test906().superpalindromesInRange("2839", "38456739538"));
}
//重要思路:先把给的数进行开方处理,然后找到回文源,把所有回文源内的数进行判断
int allnum = 0;
public int superpalindromesInRange(String L, String R) {
long sta = Long.parseLong(L);
long end = Long.parseLong(R);
//开方
long staa = (int) Math.sqrt(sta);
long endd = (int) Math.sqrt(end);
//回文源
int stAA = getA(staa);
int endD = getA(endd);
//是否重复最后一位数字
boolean stsa = (staa + "").length() % 2 == 0;
boolean ensa = (endd + "").length() % 2 == 0;
int k = ((staa + "").length() + 1) / 2;
int staL = getM(10, k - 1);
int k2 = ((endd + "").length() + 1) / 2;
int endL = getM(10, k2 - 1);
long bigin = getLong(stAA, staL, stsa);
long ended = getLong(endD, endL, ensa);
doD(stAA, endD, staL, endL, stsa, ensa);
long dBigin = bigin * bigin;
long dEnd = ended * ended;
if (dBigin >= sta && hui(dBigin)) {
allnum++;
}
if (dEnd <= end && hui(dEnd) && dEnd > dBigin) {
allnum++;
}
return allnum;
}
private void doD(int stAA, int endD, int staL, int endL, boolean stsa, boolean ensa) {
if (staL == endL && stsa == ensa) {
for (int i = stAA + 1; i <= endD - 1; i++) {
long num = getLong(i, staL, stsa);
if (hui(num * num)) {
allnum++;
}
}
return;
}
int fMax = staL * 10 - 1;
for (int i = stAA + 1; i <= fMax; i++) {
long num = getLong(i, staL, stsa);
if (hui(num * num)) {
allnum++;
}
}
int lL = staL;
boolean sa = stsa;
if (sa == true) {
lL = lL * 10;
sa = false;
} else {
sa = true;
}
//进阶顺序是:10false->10true->100false
//形成的回文分别是3位数、4位数、5位数
while (true) {
if (sa == ensa && lL == endL) {
break;
}
int min = lL;
int max = lL * 10 - 1;
for (int i = min; i <= max; i++) {
long num = getLong(i, lL, sa);
if (hui(num * num)) {
System.out.println(i);
allnum++;
}
}
if (sa == true) {
lL = lL * 10;
sa = false;
} else {
sa = true;
}
}
int lMin = lL;
if (lMin == 0) {
lMin++;
}
for (int i = lMin; i < endD; i++) {
long num = getLong(i, endL, ensa);
if (hui(num * num)) {
allnum++;
}
}
}
//判断一个数是不是回文
private boolean hui(long dEnd) {
return dEnd == getH(dEnd);
}
//找到一数的回文源的最小值,101和1001的回文源都是10
private int getA(long staa) {
int k = (staa + "").length() / 2;
return (int) staa / getM(10, k);
}
//一个数、它的大小位,加上是否双位数,如 123,100,false ->12321
private long getLong(int num, int sta, boolean sa) {
if (sa) {
int hui = getH(num, sa);
return ((long) num) * sta * 10 + hui;
} else {
int hui = getH(num, sa);
return ((long) num) * sta + hui;
}
}
//得到一个数的回文
private int getH(int num, boolean sa) {
if (!sa) {
num = num / 10;
}
return getH(num);
}
//得到一个数的回文
private int getH(int num) {
int hui = 0;
while (num > 0) {
hui = hui * 10 + num % 10;
num = num / 10;
}
return hui;
}
//得到一个数的回文
private long getH(long num) {
long hui = 0;
while (num > 0) {
hui = hui * 10 + num % 10;
num = num / 10;
}
return hui;
}
//n的k次方
private int getM(int n, int k) {
int m = 1;
for (int i = 0; i < k; i++) {
m *= n;
}
return m;
}
}