Подсчитайте количество единиц в двоичном представлении
эффективный способ подсчета числа 1s в двоичном представлении числа в O (1), Если у вас достаточно памяти для игры. Это вопрос интервью, который я нашел на онлайн-форуме, но у него не было ответа. Может кто-нибудь предложить что-то, я не могу придумать способ сделать это в O(1) Время?
21 ответов:
Это вес Хэмминга проблема, ака подсчет населения. Ссылка упоминает эффективные реализации. Цитирование:
с неограниченной памятью мы могли бы просто создать большую таблицу поиска веса Хэмминга каждого 64-битного целого числа
у меня есть решение, которое подсчитывает биты в
O(Number of 1's)время:bitcount(n): count = 0 while n > 0: count = count + 1 n = n & (n-1) return countв худшем случае (когда число 2^n - 1, Все 1 в двоичном формате) он будет проверять каждый бит.
изменить: Просто нашел очень хороший алгоритм постоянного времени, постоянной памяти для bitcount. Вот оно, написано на C:
int BitCount(unsigned int u) { unsigned int uCount; uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); return ((uCount + (uCount >> 3)) & 030707070707) % 63; }вы можете найти доказательство своей правоты здесь.
обратите внимание на то, что: n&(n-1) всегда устраняет наименее значимый 1.
следовательно, мы можем написать код для вычисления количества 1 следующим образом:
count=0; while(n!=0){ n = n&(n-1); count++; } cout<<"Number of 1's in n is: "<<count;сложность программы будет: число 1 в n (которое постоянно
Я видел следующее решение с другого сайта:
int count_one(int x){ x = (x & (0x55555555)) + ((x >> 1) & (0x55555555)); x = (x & (0x33333333)) + ((x >> 2) & (0x33333333)); x = (x & (0x0f0f0f0f)) + ((x >> 4) & (0x0f0f0f0f)); x = (x & (0x00ff00ff)) + ((x >> 8) & (0x00ff00ff)); x = (x & (0x0000ffff)) + ((x >> 16) & (0x0000ffff)); return x; }
public static void main(String[] args) { int a = 3; int orig = a; int count = 0; while(a>0) { a = a >> 1 << 1; if(orig-a==1) count++; orig = a >> 1; a = orig; } System.out.println("Number of 1s are: "+count); }
Это будет самый короткий ответ в мою жизнь так: таблица подстановки.
видимо, мне нужно немного объяснить:" если у вас достаточно памяти, чтобы играть " означает, что у нас есть вся необходимая память (неважно, техническая возможность). Теперь вам не нужно хранить таблицу поиска более одного или двух байтов. Хотя технически это будет Ω(log(n)), а не O(1), просто чтение числа, которое вам нужно, - это Ω(log (n)), поэтому, если это проблема, то ответ, невозможно - что еще короче.
какой из двух ответов они ожидают от вас на интервью, никто не знает.
есть еще один трюк: в то время как инженеры могут взять число и говорить о Ω(log(n)), где n-число, компьютерные ученые скажут, что на самом деле мы должны измерять время работы как функцию a длина ввода, поэтому то, что инженеры называют Ω(log(n)), на самом деле Ω(k), где k-количество байтов. Тем не менее, как я уже говорил, просто чтение числа-это Ω(k), поэтому мы не можем сделать лучше этого.
функция принимает
intи возвращает количество единиц в двоичном представленииpublic static int findOnes(int number) { if(number < 2) { if(number == 1) { count ++; } else { return 0; } } value = number % 2; if(number != 1 && value == 1) count ++; number /= 2; findOnes(number); return count; }
ниже приводится решение C с использованием битовых операторов:
int numberOfOneBitsInInteger(int input) { int numOneBits = 0; int currNum = input; while (currNum != 0) { if ((currNum & 1) == 1) { numOneBits++; } currNum = currNum >> 1; } return numOneBits; }следующее решение Java с использованием полномочий 2:
public static int numOnesInBinary(int n) { if (n < 0) return -1; int j = 0; while ( n > Math.pow(2, j)) j++; int result = 0; for (int i=j; i >=0; i--){ if (n >= Math.pow(2, i)) { n = (int) (n - Math.pow(2,i)); result++; } } return result; }
Ниже приведены два простых примера (в C++) среди многих, с помощью которых вы можете сделать это.
мы можем просто подсчитать набор бит (1), используя __строение_popcount().
int numOfOnes(int x) { return __builtin_popcount(x); }цикл через все биты в целое число, проверьте, если бит установлен, и если это затем увеличить переменную count.
int hammingDistance(int x) { int count = 0 for(int i = 0; i < 32; i++) if(x & (1 << i)) count++; return count; }надеюсь, что это помогает!
есть только один способ, который я могу придумать, чтобы выполнить эту задачу в O(1)... то есть "обмануть" и использовать физическое устройство (с линейным или даже параллельным программированием я думаю, что предел-O(log(k)), где k представляет количество байтов числа).
однако вы можете очень легко представить себе физическое устройство, которое соединяет каждый бит с выходной линией с напряжением 0/1. Затем вы можете просто прочитать в электронном виде общее напряжение на линии "суммирования" в O(1). Это было бы вполне легко сделать эту основную идею более элегантной с некоторыми основными элементами схемы для получения выхода в любой форме, которую вы хотите (например, двоичный кодированный выход), но основная идея одна и та же, и электронная схема будет производить правильное состояние выхода в фиксированное время.
Я предполагаю, что есть также возможные возможности квантовых вычислений, но если нам позволят это сделать, я бы подумал, что простая электронная схема-это более простое решение.
Я на самом деле сделал это, используя немного ловкости рук: одной таблицы поиска с 16 записями будет достаточно, и все, что вам нужно сделать, это разбить двоичный rep на кусочки (4-битные кортежи). Сложность на самом деле O(1), и я написал шаблон C++, который был специализирован на размере целого числа, которое вы хотели (в # битах)... делает его постоянным выражением вместо неопределенного.
fwiw вы можете использовать тот факт, что (i & - i) вернет вам LS один бит и просто цикл, зачистка выключайте lsbit каждый раз, пока целое число не станет нулем - но это старый трюк с четностью.
Я пришел сюда, имея большую веру, что я знаю красивое решение этой проблемы. Код в C:
short numberOfOnes(unsigned int d) { short count = 0; for (; (d != 0); d &= (d - 1)) ++count; return count; }но после того, как я провел небольшое исследование по этой теме (читайте другие ответы:)) я нашел 5 более эффективных алгоритмов. Люблю так!
есть даже инструкция CPU, разработанная специально для этой задачи:
popcnt. (упоминается в ответ)описание и бенчмаркинг многих алгоритмов вы можете найти здесь.
ниже метод может подсчитать количество 1s в отрицательных числах, а также.
private static int countBits(int number) { int result = 0; while(number != 0) { result += number & 1; number = number >>> 1; } return result; }однако число, подобное -1, представлено в двоичном виде как 1111111111111111111111111111111111 и поэтому потребует много сдвига. Если вы не хотите делать так много сдвигов для небольших отрицательных чисел, другой способ может быть следующим:
private static int countBits(int number) { boolean negFlag = false; if(number < 0) { negFlag = true; number = ~number; } int result = 0; while(number != 0) { result += number & 1; number = number >> 1; } return negFlag? (32-result): result; }
в python или любом другом преобразовании в строку bin затем разделите ее с помощью "0", чтобы избавиться от 0, затем объедините и получите длину.
len(''.join(str(bin(122011)).split('0')))-1
С использованием строковых операций в JS можно сделать следующим образом:
0b1111011.toString(2).split(/0|(?=.)/).length // returns 6или
0b1111011.toString(2).replace("0","").length // returns 6
Я должен был гольф это в Руби и в конечном итоге с
l=->x{x.to_s(2).count ?1}использование :
l[2**32-1] # returns 32очевидно, не эффективно, но делает трюк :)
реализация Руби
def find_consecutive_1(n) num = n.to_s(2) arr = num.split("") counter = 0 max = 0 arr.each do |x| if x.to_i==1 counter +=1 else max = counter if counter > max counter = 0 end max = counter if counter > max end max end puts find_consecutive_1(439)
двумя способами:
/* Method-1 */ int count1s(long num) { int tempCount = 0; while(num) { tempCount += (num & 1); //inc, based on right most bit checked num = num >> 1; //right shift bit by 1 } return tempCount; } /* Method-2 */ int count1s_(int num) { int tempCount = 0; std::string strNum = std::bitset< 16 >( num ).to_string(); // string conversion cout << "strNum=" << strNum << endl; for(int i=0; i<strNum.size(); i++) { if('1' == strNum[i]) { tempCount++; } } return tempCount; } /* Method-3 (algorithmically - boost string split could be used) */ 1) split the binary string over '1'. 2) count = vector (containing splits) size - 1использование::
int count = 0; count = count1s(0b00110011); cout << "count(0b00110011) = " << count << endl; //4 count = count1s(0b01110110); cout << "count(0b01110110) = " << count << endl; //5 count = count1s(0b00000000); cout << "count(0b00000000) = " << count << endl; //0 count = count1s(0b11111111); cout << "count(0b11111111) = " << count << endl; //8 count = count1s_(0b1100); cout << "count(0b1100) = " << count << endl; //2 count = count1s_(0b11111111); cout << "count(0b11111111) = " << count << endl; //8 count = count1s_(0b0); cout << "count(0b0) = " << count << endl; //0 count = count1s_(0b1); cout << "count(0b1) = " << count << endl; //1
лучший способ в javascript сделать это
function getBinaryValue(num){ return num.toString(2); } function checkOnces(binaryValue){ return binaryValue.toString().replace(/0/g, "").length; }где binaryValue-это двоичная строка, например: 1100
Comments