所以它工作正常,所需的两个主要变化只是检查x的平方根(也需要将我的检查案例从checkign翻转为余数到检查取幂)。另一个变化是使用双倍显然是鲁莽的,因为数字将超过最大双倍。
这是CodeEval的挑战,我想Facebook首先提出这个问题。这就是我的大脑立即吐出的东西。它通过所有手动测试案例(例如10-> 1,25-> 2,3-> 0)。我还没有看到任何其他解决方案,因为我想先看看我是如何用自己的想法做的。如果我离开基地,这将永远不会奏效,我会很感激有人这么说:P。如果这永远不会奏效,我必须找到一条新的方法,我会花更多的时间来讨论这个。
我不会立即看到它不会满足的情况......但这不是问题。我从来都不擅长计算运行时间的复杂性,但我认为我已经有太多的嵌套了。
我想通过左右检查(这在代码中更清楚一点),我会认真减少运行时间。我不确定这是不是就像我想的那样有效,或者其他循环仍然太多......或两者兼而有之。
有什么想法?这是可以挽救的,还是我应该废弃它并以新的方式思考它?
问题和代码如下。谢谢你看: - )
致谢:这一挑战出现在2011年的Facebook黑客杯中 双平方数是整数X,它可以表示为两个正方形的总和。例如,10是双平方,因为10 = 3 ^ 2 + 1 ^ 2。在给定X的情况下,您在此问题中的任务确定了可以将其写为两个方格的总和的方式。例如,10只能写为3 ^ 2 + 1 ^ 2(我们不计算1 ^ 2 + 3 ^ 2不同)。另一方面,25可以写成5 ^ 2 + 0 ^ 2或4 ^ 2 + 3 ^ 2 注意:不要尝试暴力攻击。不起作用。存在以下限制:
0< = X< = 2147483647
1 <= N <= 100
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class DoubleSquares {
public static void main(String[] args) throws IOException {
File file = new File(args[0]);
BufferedReader in = new BufferedReader(new FileReader(file));
String line;
while ((line = in.readLine()) != null) {
int total = 0;
String[] lineArray = line.split("\\s");
if (lineArray.length > 0) {
double x = (double) Integer.parseInt(lineArray[0]);
if (x == 0){total++;} //special case if input is 0
double sLeft = 0.00; //left boundary to indicate where to stop (so we dont repeat e.g. 4+1 and 1+4)
for(double sRight = x; sRight > sLeft; sRight--){
if (Math.sqrt(sRight) % 1 == 0){//has no remainder then it's a candidate..
double needed = x-sRight;
if (Math.sqrt(needed) % 1 == 0){//check of solution to what makes sRight == x is a perfect square.
total++; //increment if so.
}
sLeft = needed;
}
}
}
System.out.println(total);
}
}
}
为了更清楚一点,这似乎工作得很好,但是当我提交给CodeEval自动分级器时,它会在运行10秒后终止。毫无疑问,太慢或陷入一些大输入。
答案 0 :(得分:5)
Edsgar Dijkstra在其1976年的着作 The Programming of Programming 中讨论过这个问题。当 x 从 n 的整数平方根向下扫描并且 y 从零向上扫描时,Dijkstra会在一次通过中找到所有对。考虑函数B(x, y)
,该函数返回 x 和 y 之间的所有合适对,由以下三个递归规则和一个递归基数引导:
以下是我在my blog处编写解决方案的方法。我会留给你翻译成Java:
(define (squares n)
(let loop ((x (isqrt n)) (y 0) (zs '()))
(cond ((< x y) zs)
((< (+ (* x x) (* y y)) n) (loop x (+ y 1) zs))
((< n (+ (* x x) (* y y))) (loop (- x 1) y zs))
(else (loop (- x 1) (+ y 1) (cons (list x y) zs))))))
以下是一些示例,您可能会发现它们可用作测试用例:
> (squares 50)
((5 5) (7 1))
> (squares 48612265)
((5008 4851) (5139 4712) (5179 4668) (5243 4596) (5432 4371)
(5613 4136) (5656 4077) (5691 4028) (5832 3821) (5907 3704)
(6048 3469) (6124 3333) (6213 3164) (6259 3072) (6384 2803)
(6404 2757) (6413 2736) (6556 2373) (6576 2317) (6637 2136)
(6651 2092) (6756 1723) (6772 1659) (6789 1588) (6853 1284)
(6899 1008) (6917 876) (6944 627) (6948 581) (6952 531)
(6971 132) (6972 59))
> (squares 999)
()
答案 1 :(得分:1)
我的想法:
left + right = X
,请增加计数,增加左迭代器并减少右迭代器left + right > X
,请减少正确的left + right < X
,请增加左侧left
绕过right
作为优化,我们不需要在右边开始,我们可以改为对起始位置进行二元搜索。
测试代码:
private static int binarySearch(long[] a, long key)
{
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
long midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid;
}
return Math.min(low, a.length-1);
}
public static void main(String[] args)
{
long[] squares = new long[46341]; // ceil(sqrt(2147483647)) = 46341
long val = 0;
int pos = 0;
while (true)
{
long square = val*val;
// sanity check, can also use pos >= squares.length
if (square > 2147483647l)
break;
squares[pos++] = square;
val++;
}
int X = 10;
int left = 0;
int right = binarySearch(squares, X);
int count = 0;
for (; left <= right; )
{
//Collections.b
long l = squares[left] + squares[right];
if (l == X)
{
count++;
left++;
right--;
}
else if (l > X)
{
right--;
}
else
{
left++;
}
}
System.out.println(count);
}
答案 2 :(得分:0)
我的想法是:
int x1 = int(Math.sqrt(x))
long[] squares = new long[50000];
int right = binarySearch(squares,math.sqrt(x1));
int count = 0;
for(int i = 0 ; i < right; i++){
if(Math.sqrt(x-squares[i]) == int(Math.sqrt(x-squares[i]))){
count++;
} else if(int(Math.sqrt(x-squares[i])) < squares[i]) {
break;
}
}
System.out.println(x);
所以每当我们检查square数组和X中的元素之间的差异是否是一个完美的正方形时,
现在这只是我的想法,所以,当你发表评论时,请亲切一点!