题目
给定一个序列an,下标从1开始直到n,定义了以下式子:
现在要求下式的值:
小提示:
样例解释:
这里考察的是异或操作。
思路
- 首先注意到异或是支持交换律的,可将待求解的值分为两个部分:将ai全部交换到一起求出异或值,这是由输入序列确定的部分结果;还剩下一个n×n的余数矩阵,它们整体异或到一起构成输入序列个数确定的部分结果。
- 输入序列的异或结果十分简单,遍历一次输入序列,取出相异或即可,但剩下的余数矩阵如何处理?
- 再次注意到,余数矩阵在列方向上是有周期规律的:第一列是0的循环序列,第二列是1,0的循环序列,第三列是1,2,0的循环序列,第四列是1,2,3,0的循环序列,……第n列是1,2,3……n-1,0的循环序列。
- 那么先将列方向的余数相异或,第i列,偶数次循环序列相异或的结果都是0,可以抵消掉,剩余的就有单个1,2……i-1,0 序列、不完整的序列 以及单个多余的1,2……i-1,0 和一个不完整序列 1,2,……的组合这三种情况,恰好我们能够根据列序号 i 和总列数 n 的相对关系知道是何种剩余情况。
- 那么问题来了,序列1,2,3,……n-1,0的异或结果如何求解?事实上,连续整数的异或可以有O(1)复杂度的解法,详细的可以看以下两个链接,这里不进行证明:百度文库 CSDN
这里求余数矩阵单列异或结果的时间复杂度是 O(1) 的,求 n 列余数矩阵异或结果时间复杂度是O(n)的,而求解 ai 异或时间复杂度是 O(n) 的,因此整个解法是 O(n) 的。
代码
public class Solution {
public int solute(int[] array){
if(array==null || array.length==0)
return 0;
int bn = 0;
int n = array.length;
//遍历计算an
for(int i=0;i<n;i++)
bn^=array[i];
//列数从2开始,到第n列结束
for(int i=2;i<=n;i++){
//判断剩余序列个数
int remain = n - n/(2*i);
//剩余一个序列+若干数
if (remain >= i) {
int last = remain - i;
bn^=XorFrom0ToN(i-1);
bn^=XorFrom0ToN(last);
}
//剩余不足一个序列
else{
bn^=XorFrom0ToN(remain);
}
}
return bn;
}
private int XorFrom0ToN(int n){
int mod = n%4;
if(mod == 0)
return n;
else if(mod == 1)
return 1;
else if (mod == 2)
return n+1;
else
return 0;
}
}
通过测试用例57%,报错运行超时,因此可能有特殊用例没有考虑到。