JavaRush/Java блог/Архив info.javarush/подскажите алгоритм разбиения числа на цифры различными с...
Goodwin
18 уровень

подскажите алгоритм разбиения числа на цифры различными способами не переставляя.

Статья из группы Архив info.javarush
участников
Знаю, что в зависимости от длины числа получается 2^(N-1) вариантов, где N - длина числа. Например число 1234: (тогда 2^(4)=8)
  1. [1234]
  2. [1] [2] [3] [4]
  3. [1] [2] [34]
  4. [1] [23] [4]
  5. [1] [234]
  6. [12] [3] [4]
  7. [12] [34]
  8. [123] [4]
Рекурсия не подойдет, наверное, потому что мне нужно сохранять эти варианты.
Комментарии (20)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Goodwin
Уровень 18
27 июля 2015, 13:12
Спасибо Вам. Исправил условие, а то вы его не так поняли.
PolyMorph
Уровень 36
27 июля 2015, 11:29
int n = 123;
String s = "" + n;
char[] ch = s.toCharArray(); 
AlexandrRS
Уровень 41
27 июля 2015, 12:43
Это медленный способ, я думаю, что в задаче, для которой человек спрашивает, не пройдет) А точнее будет раза в 4 медленнее, чем вариант выше.
EvIv
Уровень 30
27 июля 2015, 11:07
псевдокод:

младшаяЦифра = число % 10;
число = число / 10;

повторять, пока число не станет 0.
— то есть находим остаток от деления числа на 10. Например, число 365: после первой операции имеем младшаяЦифра = 365%10 = 5;
второй строчкой «укорачиваем» наше число, чтобы дальше получить следующую с конца цифру (деление целочисленное):
число = 365/10 = 36.

Повторив шаги, получим по порядку далее цифру 6 и цифру 3. после последнего деления 3/10 = 0, выходим из цикла.

Как оформить это в код, сохраняя цифры и как исправить их порядок для ответа, оставляю как упражнение для автора =)
Goodwin
Уровень 18
27 июля 2015, 13:08
таким образом, я просто разобью на цифры, а мне нужно на различные варианты.
EvIv
Уровень 30
27 июля 2015, 13:38
на ум приходит следующее (вероятно, не самый эффективный способ):
берем числа от 0 до 2^(N — 1) и рассматриваем их двоичное представление: для N = 4
000
001
010
011
100
101
110
111

Далее «разбираем» эти числа по битам (см. побитовые операции в Java) и в случае 1 «склеиваем» соседние цифры, а в случае 0 разделяем. Реализовать можно по-разному: либо сперва разлепить все цифры как в моем первом ответе и склеивать по необходимости, либо в каждом случае разлеплять число только в нужных местах, на которые указывает бит 0 в двоичном «шаблоне», полученном выше.

000 -> 1 2 3 4
001 -> 1 2 34
010 -> 1 23 4
011 -> 1 234
и так далее

По реализации проще будет пользоваться строковым представлением чисел, а по производительности, скорее всего, лучше поиграться с арифметикой.
AndreGold
Уровень 28
27 июля 2015, 13:40
сударь, у вас немножко дезинформация
Число всех перестановок порядка n равно числу размещений из n по n, то есть факториалу
соответственно
из числа 1234, можно составить 24 варианта
EvIv
Уровень 30
27 июля 2015, 13:43
Это не перестановки. Цифры местами менять не нужно по условию задачи.
AndreGold
Уровень 28
27 июля 2015, 13:49
да не дочитал, извиняюсь
Goodwin
Уровень 18
27 июля 2015, 13:54

Заметил закономерность. буду рыть в этом направлении)) Помогите, просто устал уже. Я уже этих алгоритмов нарешался за 3 дня))
Goodwin
Уровень 18
27 июля 2015, 14:01
спасибо
AndreGold
Уровень 28
27 июля 2015, 14:30
может вам это поможет, но я обнаружил, что с каждым последующим числом, можно составить совокупностей цифр на 1 меньше. Например:
1 2 3 4
1 вариант: 1, 2, 3, 4
берем 1
2 вариант 1 234
3 вариант 12 34
4 вариант 123 4
берем 2
5 вариант 1 2 34
6 вариант 1 23 4
берем 3
7 вариант 12 3 4
EvIv
Уровень 30
27 июля 2015, 14:41
собственно, закономерность исходит из нулей и единиц в двоичном представлении, как я писал выше.

 0 0 0
1 2 3 4

 0 0 1
1 2 3-4

 0 1 0
1 2-3 4

 0 1 1
1 2-3-4

 1 0 0
1-2 3 4


Goodwin
Уровень 18
27 июля 2015, 15:28
то что надо)) согласен. выше я представил код. но он вонюч. как еще можно это реализовать? я по поводу лидирующих нулей.
Goodwin
Уровень 18
27 июля 2015, 15:30
еще раз спасибо, мне как-то и в голову не приходило через двоичное представление!!!
Goodwin
Уровень 18
27 июля 2015, 15:33
а как сделать чтобы каждое двоичное число имело лидирующие нули до размера = 2^(N-1)-1?
Вот мой говнокод)))) его можно причесать, но не суть. я проверяю строчную длину двоичного представления и если меньше 2^(N-1)-1 то добавляю лидирующие нули. Думаю все должно быть на много проще.
<code>String number = "23456808";

        int iter = (int) (Math.pow(2,(number.length()-1)) - 1);
        int length = number.length();
        for (int i = 0; i < iter; i++) {
            String bin_str = Integer.toBinaryString(i);
            if (bin_str.length() < (length - 1)) {
                bin_str = ( "" +(int) Math.pow(10,(length-1) - bin_str.length())+ bin_str).substring(1);
            }
            System.out.println(bin_str);
        }</code>
получается:
0000000
0000001
0000010
0000011
0000100
0000101
0000110
0000111
0001000
0001001
и т.д.
EvIv
Уровень 30
27 июля 2015, 16:03
Битовыми операциями можно получить эти нули и единицы и без строкового представления.
Вот пример:
<code>public static void main(String[] args) {
		int number = 125;
		for (int i = 15; i >= 0; i--) {
			if ((number & (1<<i)) != 0)
				System.out.print(1);
			else
				System.out.print(0);
		}
	}</code>
Вывод программы:
0000000001111101

Поясню что происходит в условии: (1<<i) — это единица, сдвинутая на i позиций влево в двоичном представлении числа.
& (заметьте, не &&) — это побитовое сравнение чисел, побитовый AND (если на одинаковых позициях у обоих чисел 1, то в результате на этой позиции тоже 1. Если хоть в одном 0, в результате тоже 0). Мы сравниваем побитово наше число с числом, где все нули и одна единица на нужной позиции. Так мы проверяем, есть ли в нашем числе на данной позиции единица или ноль
То есть 0100010 & 0100000 = 0100000
а 0100010 & 0010000 = 00000000
Таким образом, сравнивая результат с нулем, можно решить, что делать с соседними цифрами нашего числа: клеить или разделять.
EvIv
Уровень 30
28 июля 2015, 11:26
Получилось закодить решение?
Goodwin
Уровень 18
28 июля 2015, 12:21
Только до этого дошел, если длинна числа number = «132123432» N, то
i = 2^(N-1)-1

<code>
public ArrayList<Integer> poits(int i) {

                ArrayList<Integer> points = new ArrayList<Integer>();

                int binLen = Integer.toBinaryString(i).length();
                int binInt = Integer.parseInt(Integer.toBinaryString(i));

                for (int j = binLen-1; j >= 0; j--) {
                    if ((binInt & (1<<j)) != 0)
                        points.add(number.length() - 2 - j);
                }

                return points; 
            }
</code>
Массив points содержит индексы после которых нужно резать число в строчном выражении или опять же в массиве.
EvIv
Уровень 30
28 июля 2015, 13:11
строка
int binInt = Integer.parseInt(Integer.toBinaryString(i));

не нужна.
Она портит число, и даже если бы не портила, получилось бы, что вырыл яму и снова закопал )
А фактически получается, что из числа 12 в десятичной форма получаешь строку «1100» и его переводишь в число 1100 опять в десятичной форме. Это неверно.
Можно цикл прогнать и по исходному числу i — смотри в моем примере: я число 125 ни во что не преобразовывал. Оно в компе и так в памяти хранится в виде набора битов — в двоичном виде.