97 最大乘积问题
问题描述
小R手上有一个长度为 n 的数组 (n > 0),数组中的元素分别来自集合 [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。小R想从这个数组中选取一段连续的区间,得到可能的最大乘积。
你需要帮助小R找到最大乘积的区间,并输出这个区间的起始位置 x 和结束位置 y (x ≤ y)。如果存在多个区间乘积相同的情况,优先选择 x 更小的区间;如果 x 相同,选择 y 更小的区间。
注意:数组的起始位置为 1,结束位置为 n。
思路分析
- 考虑到乘积之后的数值特别大,观察集合中的数都满足2的指数、则乘积可以替换为加法。
- 最大乘积的终止条件为出现0时,那么乘积则一直为0,则遇到0时,则进行判断
- 由于x,y都需要最小,那么则还需要考虑为1时,乘积没有变化,但是区间增大了
代码
import java.util.Arrays;
public class Main {
public static int[] solution(int n, int[] data) {
int start = 1, end = 1;
int max = 0;
int l = 0, r = 0, sum = 0;
for (int i = 0; i < n; i++) {
if (data[i] == 0) {
if (sum > max) {
max = sum;
start = l + 1;
end = r;
}
l = i + 1;
sum = 0;
} else if (data[i] != 1) {
sum += (int)(Math.log(data[i]) / Math.log(2));
r = i + 1;
}
}
if (sum > max) {
start = l + 1;
end = r;
}
return new int[]{start, end};
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(Arrays.equals(solution(5, new int[]{1, 2, 4, 0, 8}), new int[]{1, 3}));
System.out.println(Arrays.equals(solution(7, new int[]{1, 2, 4, 8, 0, 256, 0}), new int[]{6, 6}));
}
}
复杂度分析
- 时间复杂度:O(n),因为我们需要遍历整个排列一次。
- 空间复杂度:O(1),因为我们只使用了常数级的额外空间。
后续优化
想知道要快速判断一个数是否是2的幂,并且如果是,得到它是2的几次方,可以使用位运算。具体来说,一个数 n 是2的幂,当且仅当 n & (n - 1) == 0,并且 n > 0。然后,可以通过计算 log2(n) 来得到它是2的几次方。
在Java中,可以使用以下方法来快速判断一个数是否是2的幂,并得到它是2的几次方:
public class Main {
public static int log2(int n) {
return (int) (Math.log(n) / Math.log(2));
}
public static void main(String[] args) {
int n = 64;
if ((n & (n - 1)) == 0 && n > 0) {
int power = log2(n);
System.out.println(n + " 是 2 的 " + power + " 次方");
} else {
System.out.println(n + " 不是 2 的幂");
}
}
}
解释:
-
判断是否是2的幂:
(n & (n - 1)) == 0 && n > 0n & (n - 1)的结果为0,表示n是2的幂。n > 0确保n是正数。
-
计算2的几次方:
log2(n)- 使用
Math.log(n) / Math.log(2)计算n是2的几次方。
- 使用
注意:
- 这种方法适用于判断任意整数是否是2的幂,并计算它是2的几次方。
- 对于题目中的特定集合
[0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024],可以直接使用数组索引来判断和计算。