- 给定一个数组,数组包含无数个1,2,3.
该数组作为三角的底层,已底层数据生成一个层,新车与底层的数据规则如下:
两个数相同,则新层的数字与下一层一样,两个数不同,则新一层的数据与两个数字都不相同。
示例:
1
1 1
2 3 2
2 2 1 3
3 1 3 2 1
- 函数输出结果为三角顶层的值。输入数组长度N(1<N<1024*1024),内容只会有1,2,3
先来个暴力解法,
方案1:
public void digitalPredictor(int[] array) {
for (int i = array.length; i > 0; i--) {
for (int j = 0; j < i - 1; j++) {
if (array[j] != array[j + 1]) {
array[j] = array[j] ^ array[j + 1];
}
}
}
};
显然这个方法效率很低。计算size=1024*1024,没法算。
对生成的三角,视为一个二元数组,a[size][size]
1
1 1
2 3 2
2 2 1 3
3 1 3 2 1
观察三角,发现如下情况:
设运算符为¥
当SIZE=4时,
a[3][0]=a[0][0]¥a[0][3] ,即只需要知道a[0][0]和a[0][3]就能知道Size为4情况下的三角顶点值。
对所有Size=4情况进行遍历,可以验证该猜想。
而对与任意Size内的 Size为4的小三角的三个点 a[s][t] a[s+3][t] a[s][t+3],都满足
a[s][t]=a[s+3][t]¥a[s][t+3]
即得到如下公式:
a[3^k+t][i] = a[t][i]¥a[t][i+3^k]
或者
a[s][t] = a[s-3^k][t]¥a[s-3^k][t+3^k]
即,对于与这个三角(底层为0层)任意满足层数=3^N的任意一个位置i,都能直接从0层取对应的两个数得到结果,可以计算出3^n层的所有数字。
方案2:
public static void my2(int[] array, int length) {
if (length < 4) {
for (int i = length; i > 0; i--) {
for (int j = 0; j < i - 1; j++) {
if (array[j] != array[j + 1]) {
array[j] = array[j] ^ array[j + 1];
}
}
}
System.out.println("最后" + length + "层结束");
return;
}
int base = 1;
int temp = length-1;
while (temp / 3 >= 1) {
base *= 3;
temp /= 3;
}
System.out.println("升高了" + base + "层");
// 需要计算
for (int i = 0; i <= length - 1 - base; i++) {
array[i] = array[0] == array[base + i] ? array[0] : array[0] ^ array[base + i];
}
my2(array, length - base);
}
最后结果为array[0]
计算size=1024*1024的cost=20~30ms
在计算3^n层的时候,真的需要把所有都计算出来吗?显然不需要,计算过程中做了很多无用的计算。
如果确定了跳跃计算的路径,可以知道所有需要计算的点。
以size=17举例:
可以看到,从0层跳到9层,9层跳到12层,12层到15层,15层到16层结束,中间只需要计算经过的那些点。
方案3:
public static int my3(int[] array) {
int[] step = new int[50];
int deep = 0;
int length = array.length;
if (length == 1) {
return array[0];
}
while (length > 1) {
int base = 1;
int temp = length - 1;
while (temp / 3 >= 1) {
base *= 3;
temp /= 3;
}
step[deep] = base;
deep++;
length -= base;
}
return fx(array.length - 1, 0, array, step, deep);
}
private static int fx(int r, int c, int[] arr, int[] step, int deep) {
if (r == 0) {
return arr[c];
} else {
return func(fx(r - step[deep], c, arr, step, deep - 1),
fx(r - step[deep], c + step[deep], arr, step, deep - 1));
}
}
private static int func(int a, int b) {
return a == b ? a : a ^ b;
}
计算size=1024*1024,cost=1ms~2ms