题目:
给定一个正整数数组,求或运算最大时候的最短序列。
示例:
输入: 1 2 3
输出:1
解释:1 2或运算是 3,1 2 3或运算是3,3自己也是3,最后一个长度为1,输出1.
运算:1|1 = 1,1|0 = 1,0|0 = 0
public class Num3 {
public static int getNum(int n, long[] numsArr){
if (n == 0) return 0;
int[] indexNum = new int[32];
long maxVal = numsArr[0];
long tempMaxVal = numsArr[0];
int maxLen = 1;
int tempMaxLen = 1;
String tempBinZero = Long.toBinaryString(numsArr[0]);
int lenTempBinZ = tempBinZero.length();
int tempIndexBinZ = lenTempBinZ;
while (tempIndexBinZ > 0){
tempIndexBinZ--;
if (tempBinZero.charAt(tempIndexBinZ) == '1'){
indexNum[lenTempBinZ-1-tempIndexBinZ]++;
}
}
for (int i = 1; i < n; ++i){
String tempBin = Long.toBinaryString(numsArr[i]);
int lenTempBin = tempBin.length();
int tempIndexBin = lenTempBin;
while (tempIndexBin > 0){
tempIndexBin--;
if (tempBin.charAt(tempIndexBin) == '1'){
indexNum[lenTempBin-1-tempIndexBin]++;
}
}
long indexAndPre = numsArr[i] | tempMaxVal;
int temIndexLen = tempMaxLen;
for (int j = i - temIndexLen; j < i; ++j){
boolean flag = false;//true是正常,false是删除
String tempJBin = Long.toBinaryString(numsArr[j]);
int lenTempJBin = tempJBin.length();
int tempIndexJBin = lenTempJBin;
int[] indexNumJB = new int[32];
while (tempIndexJBin > 0){
tempIndexJBin--;
if (tempJBin.charAt(tempIndexJBin) == '1'){
if (indexNum[lenTempJBin-1-tempIndexJBin] == 1){
flag = true;
break;
}
indexNumJB[lenTempJBin-1-tempIndexJBin] = 1;
}
}
if (!flag){
tempMaxLen--;
for (int k = 0; k < 32; ++k){
if (indexNumJB[k] == 1){
indexNum[k]--;
}
}
}else {
break;
}
for (int k =0; k < 32; ++k){
indexNumJB[k] = 0;
}
}
tempMaxLen++;
tempMaxVal = indexAndPre;
if (maxVal < tempMaxVal){
maxVal = tempMaxVal;
maxLen = tempMaxLen;
}else if(maxVal == tempMaxVal){
maxLen = Math.min(maxLen, tempMaxLen);
}
}
return maxLen;
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int i = 0;
long[] numsArr = new long[n];
while ( i < n){
numsArr[i] = in.nextLong();
++i;
}
System.out.println(getNum(n, numsArr));
}
}
思路详述:这题很明显是用到动态规划(不推荐暴力破解)。当遍历到第k数时有下列情况发生:
首先说明:
记录目前最大的或值maxVal和最短长度maxLen。
记录以前一个节点结尾的最大tempMaxVal和最短长度temMaxLen。
长度为32的Int数组intNum[] 用来记录以前一个节点结尾的最大tempMaxVal这个长度为temMaxLen序列中每位上的1出现的次数。
流程:
定义一个临时变量indexAndPre表示把第k个或运算到tempMaxVal后的值。(更新intNum)
目的:尽可能值不变,缩短长度。所以要从这个序列的起始位置(k-temMaxLen)开始向后遍历。得到遍历值的长度为32int[]数组的内容,同时检查当该值的数值下标对应值为1时,intNum上对应为数是否为1(如果为1,则删了这个数,temMax就变小了,如果大于1说明别的数字在这个位上也有1,可以掩盖他,可以删)。如果都不是1,那就可以删除这个数,temMaxLen--,对应的intNum--。如果有一位是一,那就跳出循环,不能删。(记得最后temMaxLen++)
完成上述后要对最大值和长度进行更新,这个好说。