编者最近遇到这样一道编程题:
问题描述:
小易有一个圆心在坐标原点的圆,小易知道圆的半径的平方。小易认为在圆上的点而且横纵坐标都是整数的点是优雅的,小易现在想寻找一个算法计算出优雅的点的个数,请你来帮帮他。
例如:半径的平方如果为25
优雅的点就有:(+/-3, +/-4), (+/-4, +/-3), (0, +/-5) (+/-5, 0),一共12个点。
输入描述:
输入为一个整数,即为圆半径的平方,范围在32位 int 范围内。
输出描述:
输出为一个整数,即为优雅的点的个数
输入例子:
25
输出例子:
12
解决方案:
问题貌似很简单,直接一个嵌套循环就行了吧?也就是说第一个for循环用于确定点的横坐标,一个嵌套的for循环用于找点的纵坐标。
编者欣然提交,然后结果显示:超时!
为什么会超时呢?仔细想想,两个 for循环的时间复杂度是O(n),而当输入的半径平方为2^31-1时,需要大量的计算时间,所以会显示超时。遇到这种情况,我们只需对原代码稍加改进,即在遍历横坐标时用二分查找法搜索满足条件的纵坐标,这样,时间复杂度就会降至O( n√log2n ),时间大大缩短,提交显示案例全部通过。
附代码:
import java.util.Scanner;
public class Elegant_Point {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int square = in.nextInt();
// int square = (int)(Math.pow(2, 31)-1);
int radius = (int)Math.sqrt(square);//半径
int cnt = 0;//优雅点的个数
int j = 0;//另一条边
if(square < 0)
cnt = 0;
else if(square == 0)
cnt = 1;
else{
// System.out.println("radius:"+radius);
for(int i = 0 ; i <= radius ; i ++){
j = Elegant_PointUtil.binarySearch(square, i, i, radius);
// System.out.println("i="+i+",j="+j);
if(j !=-1){//即存在一个数满足i*i+j*j = square
if(i == 0)
cnt += 4;
else if(i != j)
cnt += 8;
else
cnt += 4;//相等只+4
}
}
}
System.out.println(cnt);
}
}
class Elegant_PointUtil{
//返回-1表示不存在,否则返回的值满足res*res+i*i=square
public static int binarySearch(int square,int i, int low, int high){
if(low > high)
return -1;
int mid = (low+high)/2;
if(mid*mid + i*i<square){
return binarySearch(square, i, mid+1, high);
}else if(mid*mid + i*i >square)
return binarySearch(square, i, low, mid-1);
else
return mid;
}
}