正整数的二进制权重是其二进制表示中的1的数量。例如,十进制数1的二进制权重为1,十进制数7(二进制为111)的二进制权重为3.
给定正整数N,找到大于N的最小整数,其具有与N相同的二进制权重。
public static int compute(int number) {
int count = 0, nextNumber;
char[] arr = Integer.toBinaryString(number).toCharArray();
for(int i =0 ; i < arr.length ;++i) {
if(arr[i] == '1')
++count;
}
nextNumber = findNextNumber(number,count);
return nextNumber;
}
public static int findNextNumber(int number, int weight) {
char[] arr;
boolean flag = true;
int count;
while (flag) {
// increment number and convert it into char array
arr = Integer.toBinaryString(++number).toCharArray();
count = 0;
for(int i =0 ; i < arr.length; ++i) {
if(arr[i] == '1')
++count;
}
if(count == weight) {
flag = false;
}
}
return number;
}
我的解决方案工作正常,但它的复杂性似乎是O(NlogN)。可以通过其他方法在O(N)或O(log N)中实现吗?
答案 0 :(得分:1)
此操作有时称为&#34; snoob&#34;。这是一个bunch of approaches from the Hacker's Delight book。可能最好的方法是使用Integer.numberOfTrailingZeros,这可能会编译成硬件指令(未经测试):
int snoob1(int x) {
int smallest, ripple, ones; // x = xxx0 1111 0000
smallest = x & -x; // 0000 0001 0000
ripple = x + smallest; // xxx1 0000 0000
ones = x ^ ripple; // 0001 1111 0000
ones = ones >>> (2 + Integer.numberOfTrailingZeros(x)); // 0000 0000 0111
return ripple | ones; // xxx1 0000 0111
}
(&#34; 2 +&#34;部分可能存在溢出问题,因为Java移位计数是模32)
答案 1 :(得分:0)
您可以使用算法进行下一个词典排列。来自here的整数数组的Java实现。只需调整它来使用位而不是数组项:
boolean nextPermutation(int[] array) {
// Find longest non-increasing suffix
int i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i])
i--;
// Now i is the head index of the suffix
// Are we at the last permutation already?
if (i <= 0)
return false;
// Let array[i - 1] be the pivot
// Find rightmost element that exceeds the pivot
int j = array.length - 1;
while (array[j] <= array[i - 1])
j--;
// Now the value array[j] will become the new pivot
// Assertion: j >= i
// Swap the pivot with j
int temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
// Reverse the suffix
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
// Successfully computed the next permutation
return true;
}
答案 2 :(得分:0)
找出一种在O(log N)复杂度下实现相同目标的方法。
主要步骤: -
代码: -
public static int compute(int number) {
int bitPatternCategory , result;
char[] charArr = Integer.toBinaryString(number).toCharArray();
bitPatternCategory = determineNumberType(charArr);
result = findNextDesired(bitPatternCategory, charArr);
return result;
}
public static int findNextDesired(int bitPatternCategory, char[] arr) {
int number;
//System.out.print("bitPatternCategory\t"+bitPatternCategory+"\n");
char[] temp = new char[arr.length + 1];
if (bitPatternCategory == 0) {
temp = getNextForCat0(arr, temp);
} else if (bitPatternCategory == 1) {
temp = getNextForCat1(arr, temp);
} else {
temp = getNextForCat2(arr);
}
number = Integer.parseInt(String.valueOf(temp),2);
return number;
}
private static char[] getNextForCat2(char[] arr) {
// for all cases except cat 0 and 1, for example 110011000, 1001, 1101010
// Find first occurrence of 0 after 1 starting from RHS, exchange these bits and then move
// all remaining 1's(on RHS to the exchanged bits) to RHS of the array
int j =0,counterForOnes = 0;
boolean flag = false;
for (int i = arr.length - 1; i >= 0; --i) {
if ((arr[i] == '1') && (flag == false)) {
flag = true;
} else if ((arr[i] == '0') && (flag == true)) {
char tempChar = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tempChar;
j = i+2;
break;
}
}
while((j < arr.length) && (arr[j]!='0')) {
arr[j] = '0';
++counterForOnes;
++j;
}
while(counterForOnes > 0) {
arr[arr.length-counterForOnes]= '1';
counterForOnes--;
}
return arr;
}
private static char[] getNextForCat1(char[] arr, char[] temp) {
// for cases when all ones are on LHS for eg 11100, then add a new bit with value 1 and
// shift remaining 1's start from 2nd 1 towards RHS, so 1111 become 10111
int j = 1,counterForOnes= 0;
while((j < arr.length) && (arr[j]!='0')) {
arr[j] = '0';
++counterForOnes;
++j;
}
for (int i = 0; i < arr.length; ++i) {
temp[i] = arr[i];
}
temp[temp.length-1] = '0';
while(counterForOnes > 0) {
temp[temp.length-counterForOnes]= '1';
counterForOnes--;
}
arr = temp;
return arr;
}
private static char[] getNextForCat0(char[] arr, char[] temp) {
// for cases when all bits are ones only, then add a new bit with value 1 and
// shift remaining 1's start from 2nd 1 towards RHS, so 1111 become 10111
for (int i = 0; i < arr.length; ++i) {
temp[i] = arr[i];
}
for (int i = temp.length - 1; i >= 1; --i)
temp[i] = temp[i - 1];
temp[1] = '0';
arr = temp;
return arr;
}
public static int determineNumberType(char[] arr) {
int stateMachine = 0; //Category 0 for all ones for eg 111, 1111
//Category 1 for ones and zeroes 11100, 110000
//Category 2 for mix ones or we can say remaining combinations 1011, 11101
// Assuming MSB will always be 1
char temp = arr[0];
for(int i = 0 ; i < arr.length ; ++i) {
if((temp == arr[i]) && (stateMachine == 0)) {
stateMachine = 0;
} else if(((temp != arr[i])) && (stateMachine == 0)) {
stateMachine = 1;
temp = arr[i];
}else if(((temp == arr[i])) && (stateMachine == 1)) {
stateMachine = 1;
}else if(((temp != arr[i])) && (stateMachine == 1)) {
stateMachine = 2;
//temp = arr[i];
break;
}
}
return stateMachine;
}