标题:平方十位数
由0~9这10个数字不重复、不遗漏,可以组成很多10位数字。
这其中也有很多恰好是平方数(是某个数的平方)。
比如:1026753849,就是其中最小的一个平方数。
请你找出其中最大的一个平方数是多少?
注意:你需要提交的是一个10位数字,不要填写任何多余内容。
像这种题在国赛中已经算是送分题了,但是看似非常简单的一道题,然而埋藏了一个小小的陷阱。
这道题涉及的数据范围在10位整数,感觉很多人在写代码看到整数的第一反应就是定义int型,但是int在Java中是占4个字节的啊,这里只讲正数,正数最大能表示的是2^31-1,化成十进制就是2,147,483,647,数下位数刚好是10,然而大于这个数后的就不能用int表示了,最少要用到long了。
这道题我知道有两种解法,
解法一:既然不重复数字,那就把这10个数字进行全排列。对所有全排列后的得到的10位数进行开方并取整,然后对开方得到的整数再平方做比较,若两者相同,则表明这个数是平方数(举个例子:3开方后取整是1,1平方后是1,显然3不是平方数。而4开方后是2,2平方后是4,则4是平方数)。最后找出最大的那个数就行了。我一开始想到的就是这种方法,但是全排列那里消耗太多时间,运算起来非常慢,虽然填空题不考察时间复杂度问题,但是自己练习的时候要多注意,尽量选择高效的解法。并且,开方后再平方并不能保证数据一定准确,类型转换过程未免会有些失去精度。
解法二:逆向思维呗。我们想下10^10开方后是多少?不用精准计算,也能大概猜到位数是5-6位吧。那么10^11呢?一下子就能得出是10^6吧。所以,将这些10位数字开方后,得到的数字就是5位数。大约得到个范围后,将这些数进行平方运算(自己乘自己就好了),然后对结果进行分析有没重复数字。如果是从大到小遍历的,找到第一个就可以了。
以下代码用的是解法二
public class Main {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);//算下Integer最大值
//选择的最大最小值平方后在10位数范围的就行了
long min = 30000;//平方后接近10位数,足够小
long max = 100000;//平方后已经超过10位数了,足够大了
for(long i = max-1;i > min;i--) {
long plus = i * i;
if (judge(plus)) {
//从大往小遍历的,只要找到一个输出后就可以退出循环了
System.out.println(plus);
break;
}
}
//验证一下
System.out.println(Math.sqrt(9814072356d));
//这里需要强转,因为int*int后结果默认为int
System.out.println((long)99066*99066);
}
/**
* 判断是否满足条件
* @param plus
* @return
*/
private static boolean judge(long plus) {
String str = plus+"";//将数组转字符串
if (str.length() != 10) {
return false;//更严谨的判断,长度不是10就不满足条件了
}
char[] ch = str.toCharArray();//转字符串数组
boolean[] b = new boolean[10];//用于标记0-9数字是否出现过
for(int i = 0;i < ch.length;i++) {
int num = ch[i] - '0';//获取数值
if (b[num]) {//说明数字重复出现了,不满足条件了
return false;
}
b[num] = true;
}
return true;
}
}