蓝桥杯-完美平方数-java解法
- 完美平方数
- 题目
- 解法
- 1. 正向解法
- 2. 逆向解法
完美平方数
如果一个整数本身是完全平方数,它的每一位组成数字也是完全平方数,我们就称它是完美平方数。
前几个完美平方数是 0、1、4、9、49、100、144……
即第 1 个完美平方数是 0,第 2 个是 1,第 3 个是 4,……
题目
那么,第 2020 个完美平方数是多少?
解法
1. 正向解法
我们观察到,完美平方数是0及正整数,且每一位为0,1,4,9中的一个,所以可以组合拼接这四个数,然后验证拼接的数字是否能被开平方为整数。
下面上代码:
@Test
public void perfectSquareNumber() {
// 完美平方数 [解法一:使用0,1,4,9拼接组合字符,计算时间超长]
int count = 1; // 完美平方数计数
String[] eleArray = {"0", "1", "4", "9"}; // 元素组
List<Integer> current = new ArrayList<>();
current.add(0);
int rIndex = 0; // 初始化改变位置的下标
System.out.println("count=" + count + ", number=" + getCurrentStr(current, eleArray));
while (true) {
rIndex = calcRIndex(current, rIndex);
// 验证是否能被开平方
String currentStr = getCurrentStr(current, eleArray);
double sqrt = Math.sqrt(Long.parseLong(currentStr));
if (sqrt == (long) sqrt) {
count++;
System.out.println("count=" + count + ", number=" + currentStr);
if (count >= 2020) {
break;
}
}
}
}
// 计算改变位置的下标
private int calcRIndex(List<Integer> current, int rIndex) {
if (current.get(rIndex) < 3) {
current.set(rIndex, current.get(rIndex) + 1);
if (rIndex != current.size() - 1) {
rIndex = current.size() - 1;
}
} else {
// 升位或扩容
if (rIndex == 0) {
// 扩容
current.set(0, 1);
current.add(0);
rIndex = current.size() - 1;
} else {
// 升位
for (int i = rIndex; i < current.size(); i++) {
current.set(i, 0); // 复零
}
rIndex--;
return calcRIndex(current, rIndex);
}
}
return rIndex;
}
// 获取拼接的字符串
private String getCurrentStr(List<Integer> current, String[] eleArray) {
// System.out.print("current={");
StringBuilder curStr = new StringBuilder("");
for (int i = 0; i < current.size(); i++) {
// System.out.print(current.get(i) + ", ");
curStr.append(eleArray[current.get(i)]);
}
// System.out.println("}");
// System.out.println(curStr.toString());
return curStr.toString();
}
上述代码存在问题,经过较长时间(约2分钟)只计算到300+,且长度已经超过12位,从蓝桥杯测试题的选择结果来看,这个数字并未超出 Integer.MAX_VALUE=2147483647。也许,我们可以采用别的方式来求出结果。
2. 逆向解法
实际上,完美平方数的根是0及正整数,那么,我们何不从0开始递增,平方后检查该结果是否符合完美平方数呢?
说干就干:
@Test
public void perfectSquareNumber1() {
// 完美平方数 [解法二:逆向思维:完美平方数的根都是整数...]
StringBuilder squared;
int count = 1;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
squared = new StringBuilder(i * i + "");
boolean inExp = true;
for (int j = 0; j < squared.length(); j++) {
switch (squared.charAt(j)) {
case '0':
case '1':
case '4':
case '9':
break;
default:
inExp = false;
break;
}
if (!inExp) {
break;
}
}
if (inExp) {
System.out.println("count=" + count + ", number=" + squared);
if (count < 2021) {
count++;
} else {
break;
}
}
}
}
思路很简单,写起来也很快,查看控制台运行时间500ms左右,完美解决。
count=2020, number=1499441040
count=2021, number=1949990009
2022-1-11
后期有读者朋友反馈,打印的数字“时大时小”,很可疑,于是在控制台打印了用于找出完美平方数的i,发现 count=2021 时 i=13793803,显然i^2已经远远超出Integer.MAX_VALUE,所以虽然最后的结果与蓝桥杯的答案对应,但那其实是数据溢出的结果,并不是真实答案。