Получите количество двоичных чисел, которые соответствуют критериям и меньше x

Я пытаюсь получить количество (просто число, а не список) двоичных чисел, которые содержат ровно 3 единицы и меньше 1000000000, то есть: 10011, 100000011 и так далее.

Приведенный ниже код работает для целых чисел, но как заставить его работать с двоичными числами?

static void Main(string[] args)
{
    int con = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        string test = i.ToString();
        int count = test.Split('1').Length - 1;

        if (count == 3)
        {
            con++;
        }

    }

    Console.WriteLine(con);
}

person leonidas56    schedule 22.01.2018    source источник
comment
Вопрос не очень понятен, добавьте пример того, что вы хотите получить.   -  person makitocode    schedule 23.01.2018
comment
я просто хочу простое число, количество раз, которое происходит, я просто помещаю con в строку записи, но это может быть «количество двоичных чисел с тремя 1 в них» + con   -  person leonidas56    schedule 23.01.2018


Ответы (5)


Самый простой способ изменить ваш код:

static void Main(string[] args) 
{

    int con = 0;
    for (int i = 0; i < 512; i++)
    {
        string test = Convert.ToString(i, 2);
        int count = test.Split('1').Length - 1;

        if (count == 3)
        {
            con++;
        }

    }

    Console.WriteLine(con);
}

Однако это можно было бы сделать как чистое математическое уравнение:

9! / (6!*3!) = 84
person SBFrancies    schedule 22.01.2018

И для вашего дальнейшего обучения, вот еще один способ решить проблему. Мы хотим знать, сколько имеется двоичных строк, в которых ровно on включенных битов, а off выключенных битов.

Там есть несколько простых задач, которые нужно решить. N(on, off) равно единице, если on и off оба равны нулю, потому что единственным решением является пустая строка. И если любой из них равен нулю, то ответ будет один, потому что строка, состоящая из всех нулей или всех единиц, уникальна.

Давайте начнем заносить это в таблицу.

         on
      0  1  2  3  4  5
   +---------------------   
o 0|  1  1  1  1  1  1
f 1|  1
f 2|  1
  3|  1
  4|  1
  5|  1
  6|  1

Теперь, что должно идти в (1, 1)? Что ж, количество двоичных строк, в которых есть один бит включения и один бит отключения, равно количеству таких строк, начинающихся с единицы, плюс количество таких строк, начинающихся с нуля. Итак, у нас есть:

N(1, 1) = N(1, 0) + N(0, 1) = 2

А как насчет N(2, 1) ? Та же сделка:

N(2, 1) = N(1, 1) + N(2, 0) = 3

И мы видим, что аналогично N(x, 1) = N(1, x) = x + 1. Заполняем массив:

          on
      0  1  2  3  4  5
   +---------------------   
o 0|  1  1  1  1  1  1
f 1|  1  2  3  4  5  6
f 2|  1  3
  3|  1  4
  4|  1  5
  5|  1  6
  6|  1  7

вообще для вкл, выкл не ноль:

N(on, off) = N(on - 1, off) + N(on, off - 1)

что означает, что мы можем заполнить весь этот массив, многократно применяя это правило. Можете ли вы написать программу, которая делает это?

Как только вы это сделаете, вы можете просто прочитать свой ответ из массива в [6, 3].

Вы видели этот шаблон в этом массиве раньше? У него есть имя. Подсказка: вы, вероятно, не видели его в виде квадрата.

person Eric Lippert    schedule 23.01.2018

Для вашего развлечения и образования, рассмотрите следующее:

static IEnumerable<string> Combinations(int on, int off) 
{
  if (on == 0 && off == 0)
    yield return "";
  if (on > 0)
    foreach(var s in Combinations(on - 1, off))
      yield return "1" + s;
  if (off > 0)
    foreach(var s in Combinations(on, off - 1))
      yield return "0" + s;
} 

Изучите эту реализацию: она дает последовательность двоичных строк с включенными on битами и выключенными off битами. Вы видите, как это происходит?

Простой вызов .Count() для этой штуки решит вашу проблему, хотя такое решение гораздо менее эффективно, чем просто математические вычисления.

Я представляю это для вашего изучения, потому что рекурсивный перечислитель, такой как этот, является мощным инструментом при исследовании перестановок и комбинаций.

person Eric Lippert    schedule 23.01.2018

Решение без обращения к строковым представлениям:

static int CountBits(int i)
{
    var current = i;
    var bits = 0;

    while (current != 0)
    {
        if ((current & 1) == 1)
        {
            bits += 1;
        }

        current >>= 1;
    }

    return bits;
}

С помощью этого вспомогательного метода подсчет выполняется легко:

var count = Enumerable.Range(0, 0b1000000000)
                      .Count(i => CountBits(i) == 3); 

И ответ 84.

person InBetween    schedule 22.01.2018
comment
Обратите внимание, что вы можете сделать немного лучше, воспользовавшись тем фактом, что current &= current - 1; очищает нижний установленный бит; вместо того, чтобы проверять каждый бит по одному, вы можете запустить этот оператор в цикле и подсчитать, сколько раз требуется, чтобы current стало равным нулю. - person Eric Lippert; 23.01.2018
comment
@EricLippert спасибо! Я безнадежно плох, когда дело доходит до вертения бит. - person InBetween; 23.01.2018

Длинный код (сердитый стиль)

var con = 0;
for (var i = 0; i < 10000; i++)
{
    var test = i.ToString();
    if (test.Count(x => x == '1') == 3)
    {
        con++;
    }
}

Console.WriteLine(con);

Короче (более зрелый)

var con = Enumerable.Range(0, 10000)
         .Select(x => $"{x:00000}")
         .Count(x => 
             x.Count(c => c == '1') == 3
         );

Console.WriteLine(con);

PS: они оба, кажется, имеют одинаковую производительность.

person Meikel    schedule 22.01.2018
comment
Пользователь хочет проверить двоичные числа, а не десятичные числа. - person SBFrancies; 23.01.2018