Java 如何优化此算法以处理大整数?
我有两个整数x和y 规则:Java 如何优化此算法以处理大整数?,java,algorithm,optimization,Java,Algorithm,Optimization,我有两个整数x和y 规则: 如果x>y:x=x-y,y=2*y 如果y>x:y=y-x,x=2*x 如果y==x:非无限循环 问题是,这两个整数是不是一个无限循环 这是我的密码: private static boolean IsPairLoop(int first, int second) { boolean loop = false; HashMap<Integer, Integer> round_record = new HashMap<>();
private static boolean IsPairLoop(int first, int second)
{
boolean loop = false;
HashMap<Integer, Integer> round_record = new HashMap<>();
int[] first_round = new int[]{first, second};
while ((first_round[0] != -1 && first_round[1] != -1))
{
if (round_record.containsKey(first_round[0]))
{
loop = true;
break;
}
round_record.put(first_round[0], first_round[1]);
PlayRound(first_round);
}
return loop;
}
private static void PlayRound(int[] round)
{
if (round[0] > round[1])
{
round[0] -= round[1];
round[1] += round[1];
}
else if (round[0] < round[1])
{
round[1] -= round[0];
round[0] += round[0];
}
else
{
round[0] = -1;
round[1] = -1;
}
}
private静态布尔IsPairLoop(int-first,int-second)
{
布尔循环=假;
HashMap round_record=新HashMap();
int[]first_round=新int[]{first,second};
while((第一轮[0]!=-1和第一轮[1]!=-1))
{
if(第一轮[0])(第二轮记录.containsKey)
{
循环=真;
打破
}
第一轮记录。put(第一轮[0],第一轮[1]);
游戏回合(第一轮);
}
回路;
}
专用静态无效播放回合(int[]回合)
{
if(第[0]轮>第[1]轮)
{
轮[0]=轮[1];
轮[1]+=轮[1];
}
else if(第[0]轮<第[1]轮)
{
轮[1]=轮[0];
四舍五入[0]+=四舍五入[0];
}
其他的
{
四舍五入[0]=-1;
四舍五入[1]=-1;
}
}
这适用于小整数。然而,当整数差真的很大时,这是非常缓慢的。x和y的整数范围均为1到2^30。即使在整数差很大的情况下,我该怎么做才能使这个速度更快?使用Floyd的循环检测算法,而不是使用hashmap。这不仅可以避免大量内存使用,还可以避免在
int
和Integer
之间进行昂贵的装箱和拆箱
第二个优化是通过变量的变化重新写入递推关系:
s = x+y
t = x-y
然后递归关系变成:
if t=0, stop
if t>0, s'=s, t'=2t-s
if t<0, s'=s, t'=2t+s
如果first+second
可能溢出,您可能需要将int
替换为long
我认为,给定前提条件,你永远不会得到一个无限大的
t
(因为|t |
总是正确的)。但是您可能希望进行双重检查,也许可以在代码中添加某种断言。使用Floyd的循环检测算法,而不是使用hashmap。这不仅可以避免大量内存使用,还可以避免在int
和Integer
之间进行昂贵的装箱和拆箱
第二个优化是通过变量的变化重新写入递推关系:
s = x+y
t = x-y
然后递归关系变成:
if t=0, stop
if t>0, s'=s, t'=2t-s
if t<0, s'=s, t'=2t+s
如果first+second
可能溢出,您可能需要将int
替换为long
我认为,给定前提条件,你永远不会得到一个无限大的
t
(因为|t |
总是正确的)。但是,您可能希望进行双重检查,或许可以在代码中添加某种断言。让我们向后看一看。什么能产生x==y?前一个x和y之间的差值必须等于两者中较小者的两倍,即较大者必须是较小者的三倍。到目前为止没有无限循环的事物:
- {n,n}
- {n,3n}
- n是不同的a− b对于某些a>b,且3n=2b
3(a)− b) =2b
3a− 3b=2b
3a=5b
a=5/3 b 一对{m,5/3m}是在下一步产生{n,3n}的东西。(m必须能被3整除,但这没关系。) - 3n是一种差异a− 对于某些a>b,n=2b
(一)− b) /3=2b
A.− b=6b
a=7b 一对{m,7m}是下一步唯一能产生{n,3n}的东西
- {n,n}
- {n,3n}
- {n,7n}
- {n,5/3 n}
- n是不同的a− 对于某些a>b,且qn=2b
q(a)− b) =2b
质量保证− qb=2b
qa=(2+q)b
a=(2+q)/qb - 或者qn是一个不同点− 对于某些a>b,n=2b
(一)− b) /q=2b
A.− b=2qb
a=(2q+1)b
- (2n+m)/m
- (2m+n)/n
- (2+1)/1=3
- 2×1+1=3
- 三,
- (2+3)/3=5/3
- 2×3+1=7
- 三,
- 5/3
- 七,
- (2+5/3)/(5/3)=(6+5)/5=11/5
- (2×5/3)+1=10/3+1=13/3
- 三,
- 5/3
- 七,
- 11/5
- 13/3
- (2+7)/7=9/7
- 2×7+1=15
- 3/1
- 5/3
- 7/1
- 9/7
- 11/5
- 13/3
- 15/1
3/1
7/1
15/1
31/1
63/1
5/3
13/3
29/3
61/3
11/5
27/5
59/5
9/7
25/7
57/7
23/9
55/9
21/11
53/11
19/13
51/13
17/15
49/15
47/17
45/19
43/21
41/23
39/25
37/27
35/29
33/31
看起来非常像m/n,其中n是奇数,m>n,m+n是2的幂。因此,优化算法的一种方法是:
private static boolean isPairLoop(int first, int second)
{
if (first == second) return false;
if (first > second) return isPairLoop(second, first);
if (first == 0) return true;
int d = gcd(first, second);
return Integer.bitCount(first / d + second / d) != 1;
}
private static int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
在bigint上的位数上花费二次时间
现在你只需要证明它是有效的。我希望它能起作用。让我们倒过来看看。什么能产生x==y?前一个x和y之间的差值必须等于两者中较小者的两倍,即较大者必须是较小者的三倍。到目前为止没有无限循环的事物:
- {n,n}
- {n,3n}
- n是不同的a− b对于某些a>b,且3n=2b
3(a)− b) =2b
3a− 3b=2b
3a=5b
a=5/3 b 一对{m,5/3m}是在下一步产生{n,3n}的东西。(m必须能被3整除,但这没关系。)