我正在研究一个带整数的程序,并找到整数所具有的连续和的组合数:
数字13可以表示为连续阳性的总和 整数6 + 7.十四可以表示为2 + 3 + 4 + 5,也是一个和 连续正整数。有些数字可以表示为a 不止一种方式的连续正整数之和。对于 例如,25是12 + 13,也是3 + 4 + 5 + 6 + 7。
我研究并发现它是奇数因子减去1的数量。所以我写了一个程序来查找奇数因子的数量,在某些情况下我的答案仍然是错误的。有什么见解吗?
代码似乎工作正常,但是由于超时导致崩溃,这可能是由于优化错误。
可能的输入大小的约束是 1至10 ^(12)
以下代码是从以下alfasin's answer复制的:
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
static long consecutive(long num) {
while (num % 2 == 0) num /= 2;
return consecutiveHelper(num);
}
public static long consecutiveHelper(long num) {
return LongStream.rangeClosed(3, (num / 2)).parallel().filter(x -> x % 2 != 0).map(fn -> (num % fn == 0) ? 1 : 0).sum();
}
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
final String fileName = System.getenv("OUTPUT_PATH");
BufferedWriter bw = null;
if (fileName != null) {
bw = new BufferedWriter(new FileWriter(fileName));
}
else {
bw = new BufferedWriter(new OutputStreamWriter(System.out));
}
int res;
long num;
num = Long.parseLong(in.nextLine().trim());
res = consecutive(num);
bw.write(String.valueOf(res));
bw.newLine();
bw.close();
}
}
这就是我目前所拥有的
答案 0 :(得分:3)
您需要做的是在素数因子中分解您的数字。
例如,如果你采用 1200 :
1200 = 2*2*2*2*3*5*5 = 1 * 2^4 * 3^1 * 5^2
然后,您可以分析如何使用这些素数因子获得奇数因子。快速分析会告诉您:
考虑到这一点,让我们找到我们用奇数*奇数得到的所有因素:
快速找到这些组合而不全写它们的方法是“加1方法”:将每个主要奇数因子的出现次数加1,并将加在一起< / strong>:
我们发现1200 = 1 * 2^4 * 3^1 * 5^2
,所以我们可以这样做:
(1 + 1) ( 2 + 1) = 6
数字1200有6个奇数因子,如您所述,从该数字中删除1以获得1200具有的连续总和组合数:
现在,让我们看看代码。 我们想要的是地图,关键是主要因素,价值是他们出现的次数:
/*
If number is odd,
find the number in the keys and add 1 to its value.
If the number is not in the keys, add it with value = 1.
*/
public static void addValue(Map<Integer, Integer> factors, int i) {
if(i % 2 != 0) {
int count = factors.containsKey(i) ? factors.get(i) : 0;
factors.put(i, ++count);
}
}
/*
Classic algorithm to find prime numbers
*/
public static Map<Integer, Integer> oddPrimeFactors(int number) {
int n = number;
Map<Integer, Integer> factors = new HashMap<>();
for (int i = 2; i <= n / i; i++) {
while (n % i == 0) {
addValue(factors, i);
n /= i;
}
}
if(n > 1) addValue(factors, n);
return factors;
}
有了这个,让我们尝试打印地图中包含数字 1200 的内容:
public static void main(String[] args) {
int n = 1200;
System.out.println(oddPrimeFactors(n));
}
$n : {3=1, 5=2}
好的!现在让我们用我们之前开发的方法完成程序:
public static int combinations = 1;
public static void main(String[] args) {
int n = 1200;
oddPrimeFactors(n).forEach((key, value) -> combinations *= (value + 1));
combinations--;
System.out.println(combinations);
}
$combinations = 5
完了!随便问你是否理解不了什么!
注意:我尝试使用Integer可以处理的最大值的程序,并且我的程序继续花费不到一秒钟,这对我来说似乎相当快。它可能会更快,你可以找到这个代码的最优化版本!
答案 1 :(得分:0)
以下是我们在评论部分讨论的优化,请参阅评论作为标记:
static int consecutive(long num) {
while (num % 2 == 0) num /= 2; // 1st opt.
return consecutiveHelper(num)-1;
}
public static int consecutiveHelper(long num) {
long factorNumber = 1;
int count = 0;
while(factorNumber <= num / 2) { // 2nd opt.
if(num % factorNumber == 0) {
count++;
}
factorNumber += 2; // 3rd opt.
}
if (num % 2 != 0) {
count++;
}
return count;
}
<强>更新强>
通过使用Java 8 Stream接口并且并行运行,我设法减少了大数字(10 ^ 12)的运行时间约50%:
static long consecutive(long num) {
while (num % 2 == 0) num /= 2;
return consecutiveHelper(num);
}
public static long consecutiveHelper(long num) {
return LongStream
.rangeClosed(3, (num / 2))
.parallel()
.filter(x -> x % 2 != 0)
.map(fn -> (num % fn == 0) ? 1 : 0)
.sum();
}
也就是说,当您处理较小的数字时,并行将会更加昂贵。如果你希望你的答案是最优的,你应该使用两种方法:对于较小的数字使用第一种,而对于大数字则使用后者。