Следующее решение заимствовано из моей книги « Интервью по кодированию: вопросы, анализ и решения »:
Выбраны некоторые целые числа в массиве, которые составляют комбинацию. Используется набор бит, где каждый бит обозначает целое число в массиве. Если для комбинации выбран символ i-го , бит i-го равен 1; в противном случае это 0. Например, три бита используются для комбинаций массива [1, 2, 3]. Если первые два целых числа 1 и 2 выбраны для составления комбинации [1, 2], соответствующие биты являются {1, 1, 0}. Аналогично, биты, соответствующие другой комбинации [1, 3], являются {1, 0, 1}. Мы можем получить все комбинации массива с длиной n , если мы сможем получить все возможные комбинации битов n .
Число состоит из набор бит. Все возможные комбинации битов n соответствуют номерам от 1 до 2 ^ n -1. Поэтому каждому числу в диапазоне от 1 до 2 ^ n -1 соответствует комбинация массива с длиной n . Например, число 6 состоит из битов {1, 1, 0}, поэтому первый и второй символы выбираются в массиве [1, 2, 3] для генерации комбинации [1, 2]. Аналогично, число 5 с битами {1, 0, 1} соответствует комбинации [1, 3].
Код Java для реализации этого решения выглядит следующим образом:
public static ArrayList> powerSet(int[] numbers) {
ArrayList> combinations = new ArrayList>();
BitSet bits = new BitSet(numbers.length);
do{
combinations.add(getCombination(numbers, bits));
}while(increment(bits, numbers.length));
return combinations;
}
private static boolean increment(BitSet bits, int length) {
int index = length - 1;
while(index >= 0 && bits.get(index)) {
bits.clear(index);
--index;
}
if(index < 0)
return false;
bits.set(index);
return true;
}
private static ArrayList getCombination(int[] numbers, BitSet bits){
ArrayList combination = new ArrayList();
for(int i = 0; i < numbers.length; ++i) {
if(bits.get(i))
combination.add(numbers[i]);
}
return combination;
}
Приращение метода увеличивает число, представленное в наборе бит. Алгоритм очищает 1 бит от самого правого до тех пор, пока не будет найден 0 бит. Затем он устанавливает самый правый бит 0 в 1. Например, чтобы увеличить число 5 с битами {1, 0, 1}, он очищает 1 бит с правой стороны и устанавливает крайний правый бит 0 в 1. Биты становятся {1, 1, 0} для числа 6, что является результатом увеличения 5 на 1.