第八届蓝桥杯国赛 JavaB组 第一题 标题:平方十位数

标题:平方十位数

由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;
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值