Выяснил подход для достижения того же в сложности O (log N).
Основные шаги: -
- Преобразование числа в двоичный массив символов. (Довольно просто).
- Категоризация двоичного массива на основе их шаблона. (Объясняется в комментариях)
- На основе категории отрегулируйте 0 и 1 двоичного массива.
- Преобразование двоичного массива символов обратно в число.
Код: -
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;
}