Алгоритм генерации уникальных чисел

168
03 ноября 2019, 13:50

Есть число N, необходимо найти все уникальные числа до 0 до N. Например из чисел 123,132,213,231,312,321 уникальным будет только любое одно, но если N = 321, то скорее всего уникальным будет 123 т.к. в переборе встретиться первым. Простой перебор не подходит, т.к. для long значений он становится очень долгим.

boolean isNext = false;
   long num; //Входящее число
   long digit;
   long digit2;
   while (num > 0) {
        digit = num % 10;
        digit2 = num / 10;
        if (digit >= digit2 % 10) {
            isNext = true;
        } else {
            isNext = false;
            break;
        }
        num /= 10;
   }
Answer 1

Частичное решение вашей задачи.

Позволяет найти все числа с уникальными комбинациями цифр для указанного количества знаков (n). Не хватает остановки при достижении указанного числа N - ищет все возможные n-значные числа.

Например: найти все уникальные 4-х значные числа - алгоритм найдет все числа от 1 до 9999. Найти все 3-х значные - найдёт числа от 1 до 999.

Определение уникального числа:

Уникальным считается то число, которое имеет комбинацию цифр отличную от всех чисел проверенных ранее.

Пример 1. Все уникальные двухзначные числа (10 - 99):

Число 21 не является уникальным, так как имеет ту же комбинации цифр, что и число 12, проверенное ранее.

Число 14 является уникальным, так как это первый из двух возможных вариантов комбинации цифр 1 и 4. Вторым вариантом является число 41, но оно ещё не встречалось (соответственно, когда мы до него дойдём оно уже не будет уникальным).

Пример 2. Уникальные трёхзначные числа от 100 до 199:

Решение:

Предлагаю не проверять все числа на уникальность перебором, а изначально конструировать только уникальные комбинации цифр. Для простоты возьмём числа без нулей (нули требуют дополнительной обработки):

1) Первая цифра любого числа может иметь только девять вариантов: 1, 2, 3 ... 9. Мы будем собирать комбинации для каждой стартовой цифры отдельно - в виде строки. Конечно, нет нужды делать это одновременно, подойдёт цикл прокручивающий числа от 1 до 9 и выполняющий все требуемые действия для каждой строки по очереди.

Итак, возьмём девять начал состоящих из 1 цифры:

# В квадратных скобках зафиксированная (неизменяемая) часть
# состоящая из одной цифры.
[1] -> в эту сторону будет расти число
[2] -> в эту сторону будет расти число
[3] -> в эту сторону будет расти число
[4]
[5]
[6]
[7]
[8]
[9]

Можно представлять вместо чисел кубики - вначале у нас 9 рядов по одному кубику, на следующем шаге мы добавляем справа ещё по одному кубику, потом ещё и т. д. до требуемого количества кубиков (знаков) в ряде.

2) Если текущая цифра равна 1, то следующая цифра тоже должна быть 1 или больше и так для каждой последующей цифры. Меньше она быть не может, так как в этом случае мы получим уже пройденную комбинацию. То есть 23 - новая уникальная комбинация, а 21 уже была найдена ранее в числе 12.

[1] <- 1 #присоединяем 1 к уже имеющейся строке.
[2] <- 2 #присоединяем 2 к уже имеющейся строке.
[3] <- 3
[4] <- 4
[5]5
[6]6
[7]7
[8]8
[9]9

Обратите внимание, что первая цифра у нас зафиксирована, а вторую мы будем менять, создавая таким образом все возможны двухзначные комбинации.

3) Присоединяем к фиксированная части следующую цифру (предыдущая цифра + 1), до тех пор, пока она не будет равна 9. Видно, что для числа 99 уже не будет новых комбинаций. А для числа 11 их ещё 8 - 12, 13, 14, 15, 16, 17, 18, 19. Дойдя в каждом ряде до цифры 9 мы получим все возможные комбинации для конкретной стартовой цифры. А соединив все результаты воедино - все возможные комбинации для данного количества знаков, - что и требовалось.

[1] <- 2 #увеличиваем текущую цифру на 1 и добаляем к уже имеющейся строке.
[2] <- 3 #увеличиваем текущую цифру на 1 и добаляем к уже имеющейся строке.
[3] <- 4 #увеличиваем текущую цифру на 1 и добаляем к уже имеющейся строке.
[4] <- 5 #увеличиваем текущую цифру на 1 и добаляем к уже имеющейся строке.
[5]6
[6]7
[7]8
[8]9
[9]9 #данная комбинация, начинающаяся с 9 достигла своего предела.

4) Если нужно собрать трёхзначные комбинации, то берём всё возможные двухзначные комбинации полученные на предыдущем этапе, фиксируем их в виде строки и повторяем все шаги, начиная с пункт 1. Делать это удобно с помощью рекурсии.

# В квадратных скобках зафиксированная часть
# состоящая из двух цифр.
[11] <- 1 #присоединяем 1 к уже имеющейся строке.
[22] <- 2 #присоединяем 2 к уже имеющейся строке.
[33]3     
[44]4
[55]5
[66]6
[77]7
[88]8
[99]9

Реализация на Python:

# head - здесь фиксируется стартовая часть каждой комбинации
###
# start - точка отсчёта для новых комбинаций
###
# digit_num - количество знаков для которого требуется найти комбинации.
# 4 == 3 знака, 3 == 2 знака и т.д.
###
# depth - отслеживаем глубину рекурсии, чтобы остановить её в нужный момент.
# Также используется для понимания порядкового номера знака над которым работаем
# в данный момент. 
def print_uniq_nums(head, start, digit_num, depth):
    if depth >= digit_num:
        return
    if depth > 0:
        print(head)
    # запускаем счётчик от 0 до 9
    # если нули можно было бы не учитывать, как в моём упрощённом
    # объяснении, то можно было начинать отсчёт со  "start",
    # а так как они нужны, то начинаем от нуля, потом пропускаем ненужное
    # и продолжаем со "start"
    for i in range(0, 10):      
        # Чтобы не создавало комбинации типа 001, 002 и т.д.
        if i == 0 and depth == 0:
            continue
        # Для защиты от неправильных комбинаций типа:
        # 110 (уже была: 101), 220 (уже была: 202)
        if i == 0 and depth > 1 and head[depth - 1] != "0":
            continue        
        if i == 0 or i >= start:                
            # прибавляем к фиксированной части, находящейся в head,
            # изменямое окончание и отдаём получившуюся комбинацию
            # на следующий уровень рекурсии
            num_str = "%s%s" % (head, i)
            # Если i == 0, то пробрасываем текущую точку отсчёта
            # на следующий уровень рекурсии, чтобы после
            # нулей счётчик не сбивался. 
            # Иначе будет неправильная комбинация 2001, вместо 2002
            if i > 0:
                start = i
            print_uniq_nums(num_str, start, digit_num, depth + 1)
print_uniq_nums("", 1, 4, 0)

Output (сокращённый):

1
10
100
101
102
103
104
105
106
107
108
109
11
111
112
..............
119
12
122
..............
128
129
13
133
..............
2
20
200
202
..............
207
208
209
22
222
223
..............

Другой вариант решения:

Перебираем все числа от 0 до N, каждое разбиваем на отдельные цифры и укладываем в массив. Массив сортируем, формируем из него строку, делаем её хэш и добавляем его в хэш-таблицу. В качестве ключа используем получившийся хэш, в качестве значения - 1. При нахождении следующего числа с такой же комбинацией цифр, увидим, что в хэш-таблице уже есть такой элемент, значит, это число пропускаем.

Answer 2

Представляю свой алгоритм:

int [] array={2,3,4,5,4,3,2,1};
list<int> list;
for(int i=0;i<array.length;i++)
 {      
int count=0;
   for(int j=0;j<array.length;j++)
    {   
        if(array[i]==array[j]) count++;
    } 
   if(count==0) list.Add(arra[i]);  // добавляем в список или в любой контейнер
 }
READ ALSO
Как обратиться к API VK через node-vk-bot-api

Как обратиться к API VK через node-vk-bot-api

Есть библиотека - node-vk-bot-api Как с помощью нее обратиться например за методом usersget (возвращающее информацию о профиле)

129
Экспорт данных в excel из html на javascript

Экспорт данных в excel из html на javascript

На сервере или на клиенте грамотно делать генерацию excel файлов? Таблица для экспорта сделана на флексахНа клиентской стороне на js нормально...

129
Динамический диалог на php js ajax

Динамический диалог на php js ajax

Задача такая создать динамический диалог на ajax js и phpЗадача вроде выполнена, но при использовании данной функции создается куча запросов...

117