Ниже метод вернет вам значение от 10000000000 до 9999999999
long min = 1000000000L
long max = 9999999999L
public static long getRandomNumber(long min, long max){
Random random = new Random();
return random.nextLong() % (max - min) + max;
}
Искусство Объема Программирования 4: Гроздь 3 имеет тонну их, которые могли бы соответствовать Вашей конкретной ситуации лучше, чем, как я описываю.
проблемой, с которой Вы столкнетесь, является, конечно, память и довольно быстро, у Вас будут проблемы 20 элементами в Вашем наборе - <глоток> 20 глоток> C3 = 1140. И если Вы хотите выполнить итерации по набору, лучше использовать измененный алгоритм кода Грея, таким образом, Вы не держите всех их в памяти. Они генерируют следующую комбинацию от предыдущего и избегают повторений. Существуют многие из них для различного использования. Мы хотим максимизировать различия между последовательными комбинациями? минимизировать? и так далее.
Некоторые исходные бумаги, описывающие коды Грея:
Вот некоторые другие бумаги, затрагивающие тему:
Phillip J Преследование, ' Алгоритм 382: Комбинации M из Объектов N ' (1970)
алгоритм в C...
можно также сослаться на комбинацию ее индексом (в лексикографическом порядке). Понимание, что индекс должен быть некоторым количеством изменения справа налево на основе индекса, мы можем создать что-то, что должно восстановить комбинацию.
Так, у нас есть набор {1,2,3,4,5,6}..., и мы хотим три элемента. Скажем, {1,2,3} мы можем сказать, что различие между элементами один и в порядке и минимально. {1,2,4} имеет одно изменение и лексикографически номер 2. Таким образом, количество 'изменений' в последнем месте составляет одно изменение в лексикографическом упорядочивании. Второе место, с одним изменением {1,3,4} имеет одно изменение, но составляет больше изменения, так как это во-вторых (пропорционально числу элементов в исходном наборе).
метод, который я описал, является разрушением, как это кажется от набора до индекса, мы должны сделать реверс †“, который намного более хитер. Это - то, как Застежки решают проблему. Я записал [приблизительно 1 116] C для вычисления их с незначительными изменениями †“, я использовал индекс наборов, а не диапазона числа для представления набора, таким образом, мы всегда работаем от 0... n.Примечание:
существует иначе : его понятие легче схватить и программировать, но это без оптимизации Застежек. К счастью, это также не производит дублирующиеся комбинации:
набор , который максимизирует , где .
Для примера: 27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Так, 27-я лексикографическая комбинация четырех вещей: {1,2,5,6}, те - индексы любого набора, на который Вы хотите посмотреть. Пример ниже (OCaml), требует choose
функция, оставленная читателю:
(* this will find the [x] combination of a [set] list when taking [k] elements *)
let combination_maccaffery set k x =
(* maximize function -- maximize a that is aCb *)
(* return largest c where c < i and choose(c,i) <= z *)
let rec maximize a b x =
if (choose a b ) <= x then a else maximize (a-1) b x
in
let rec iterate n x i = match i with
| 0 -> []
| i ->
let max = maximize n i x in
max :: iterate n (x - (choose max i)) (i-1)
in
if x < 0 then failwith "errors" else
let idxs = iterate (List.length set) x k in
List.map (List.nth set) (List.sort (-) idxs)
следующие два алгоритма предоставлены для дидактических целей. Они реализуют итератор и (более общее) папка полные комбинации. Они максимально быстро, имея сложность O (<глоток> n глоток> C k). Потребление памяти связывается k
.
Мы запустим с итератора, который назовет пользователя предоставленным функции для каждой комбинации
let iter_combs n k f =
let rec iter v s j =
if j = k then f v
else for i = s to n - 1 do iter (i::v) (i+1) (j+1) done in
iter [] 0 0
А, более общая версия назовет пользователя предоставленным функции наряду с переменной состояния, начинающей с начального состояния. Так как мы должны передать состояние между различными состояниями, мы не будем использовать для цикла, но вместо этого, использовать рекурсию,
let fold_combs n k f x =
let rec loop i s c x =
if i < n then
loop (i+1) s c @@
let c = i::c and s = s + 1 and i = i + 1 in
if s < k then loop i s c x else f c x
else x in
loop 0 0 [] x
Если можно использовать синтаксис SQL - говорят, если Вы используете LINQ для доступа к полям структуры или массива, или непосредственно получаете доступ к базе данных, которая имеет таблицу под названием "Алфавит" со всего одним символьным полем "Letter", можно адаптировать следующий код:
SELECT A.Letter, B.Letter, C.Letter
FROM Alphabet AS A, Alphabet AS B, Alphabet AS C
WHERE A.Letter<>B.Letter AND A.Letter<>C.Letter AND B.Letter<>C.Letter
AND A.Letter<B.Letter AND B.Letter<C.Letter
Это возвратит все комбинации 3 букв, несмотря на это, сколько букв Вы имеете в таблице "Alphabet" (это может быть 3, 8, 10, 27, и т.д.).
, Если то, что Вы хотите, является всеми перестановками, а не комбинациями (т.е. Вы хотите, чтобы "ACB" и "ABC" рассчитали как отличающиеся, а не появились только однажды), просто удаляют последнюю строку (И один), и это сделано.
Постредактирование: После перечитывания вопроса я понимаю то, что необходимо, общие алгоритм, не только определенный для случая выбора 3 объектов. Ответ Adam Hughes является полным, к сожалению, я (еще) не могу проголосовать за него. Этот простой ответ, но работы только для того, когда Вы хотите точно 3 объекта.
static IEnumerable<string> Combinations(List<string> characters, int length)
{
for (int i = 0; i < characters.Count; i++)
{
// only want 1 character, just return this one
if (length == 1)
yield return characters[i];
// want more than one character, return this one plus all combinations one shorter
// only use characters after the current one for the rest of the combinations
else
foreach (string next in Combinations(characters.GetRange(i + 1, characters.Count - (i + 1)), length - 1))
yield return characters[i] + next;
}
}
Следующий рекурсивный алгоритм выбирает все комбинации k-элемента от упорядоченного множества:
i
из Вашей комбинации i
с каждой из комбинаций k-1
элементы, выбранные рекурсивно из набора элементов, больше, чем i
. Выполняют итерации вышеупомянутого для каждого i
в наборе.
важно, чтобы Вы выбрали остальную часть элементов как больше, чем i
, для предотвращения повторения. Этот путь [3,5] будет выбран только однажды, как [3] объединенный с [5], вместо дважды (условие устраняет [5] + [3]). Без этого условия Вы получаете изменения вместо комбинаций.
Позволяет говорят, что Ваш массив букв похож на это: "ABCDEFGH". У Вас есть три индекса (я, j, k) указание, которое обозначает буквами Вас, собираются использовать для текущего слова, Вы запускаете с:
A B C D E F G H ^ ^ ^ i j k
Первый Вы варьируетесь k, таким образом, следующий шаг похож на это:
A B C D E F G H ^ ^ ^ i j k
при достижении конца Вы продолжаете и варьируетесь j и затем k снова.
A B C D E F G H ^ ^ ^ i j k A B C D E F G H ^ ^ ^ i j k
Однажды Вы j достигнутый G Вы начинаете также варьироваться я.
A B C D E F G H ^ ^ ^ i j k A B C D E F G H ^ ^ ^ i j k ...
Записанный в коде этот взгляд что-то как этот
void print_combinations(const char *string)
{
int i, j, k;
int len = strlen(string);
for (i = 0; i < len - 2; i++)
{
for (j = i + 1; j < len - 1; j++)
{
for (k = j + 1; k < len; k++)
printf("%c%c%c\n", string[i], string[j], string[k]);
}
}
}
Вот мое суждение в C++
, я пытался ввести такое небольшое ограничение на тип итератора, как я мог так это решение принимать просто вперед итератор, и это может быть const_iterator. Это должно работать с любым стандартным контейнером. В случаях, где аргументы не имеют смысла, он бросает станд.:: invalid_argumnent
#include <vector>
#include <stdexcept>
template <typename Fci> // Fci - forward const iterator
std::vector<std::vector<Fci> >
enumerate_combinations(Fci begin, Fci end, unsigned int combination_size)
{
if(begin == end && combination_size > 0u)
throw std::invalid_argument("empty set and positive combination size!");
std::vector<std::vector<Fci> > result; // empty set of combinations
if(combination_size == 0u) return result; // there is exactly one combination of
// size 0 - emty set
std::vector<Fci> current_combination;
current_combination.reserve(combination_size + 1u); // I reserve one aditional slot
// in my vector to store
// the end sentinel there.
// The code is cleaner thanks to that
for(unsigned int i = 0u; i < combination_size && begin != end; ++i, ++begin)
{
current_combination.push_back(begin); // Construction of the first combination
}
// Since I assume the itarators support only incrementing, I have to iterate over
// the set to get its size, which is expensive. Here I had to itrate anyway to
// produce the first cobination, so I use the loop to also check the size.
if(current_combination.size() < combination_size)
throw std::invalid_argument("combination size > set size!");
result.push_back(current_combination); // Store the first combination in the results set
current_combination.push_back(end); // Here I add mentioned earlier sentinel to
// simplyfy rest of the code. If I did it
// earlier, previous statement would get ugly.
while(true)
{
unsigned int i = combination_size;
Fci tmp; // Thanks to the sentinel I can find first
do // iterator to change, simply by scaning
{ // from right to left and looking for the
tmp = current_combination[--i]; // first "bubble". The fact, that it's
++tmp; // a forward iterator makes it ugly but I
} // can't help it.
while(i > 0u && tmp == current_combination[i + 1u]);
// Here is probably my most obfuscated expression.
// Loop above looks for a "bubble". If there is no "bubble", that means, that
// current_combination is the last combination, Expression in the if statement
// below evaluates to true and the function exits returning result.
// If the "bubble" is found however, the ststement below has a sideeffect of
// incrementing the first iterator to the left of the "bubble".
if(++current_combination[i] == current_combination[i + 1u])
return result;
// Rest of the code sets posiotons of the rest of the iterstors
// (if there are any), that are to the right of the incremented one,
// to form next combination
while(++i < combination_size)
{
current_combination[i] = current_combination[i - 1u];
++current_combination[i];
}
// Below is the ugly side of using the sentinel. Well it had to haave some
// disadvantage. Try without it.
result.push_back(std::vector<Fci>(current_combination.begin(),
current_combination.end() - 1));
}
}
У меня был алгоритм перестановки, который я использовал для Эйлера проекта в Python:
def missing(miss,src):
"Returns the list of items in src not present in miss"
return [i for i in src if i not in miss]
def permutation_gen(n,l):
"Generates all the permutations of n items of the l list"
for i in l:
if n<=1: yield [i]
r = [i]
for j in permutation_gen(n-1,missing([i],l)): yield r+j
, Если
n<len(l)
у Вас должна быть вся комбинация, Вам нужно без повторения, Вам нужен он?
Это - генератор, таким образом, Вы используете его в чем-то вроде этого:
for comb in permutation_gen(3,list("ABCDEFGH")):
print comb
В Python как Andrea Ambu, но не hardcoded для выбора три.
def combinations(list, k):
"""Choose combinations of list, choosing k elements(no repeats)"""
if len(list) < k:
return []
else:
seq = [i for i in range(k)]
while seq:
print [list[index] for index in seq]
seq = get_next_combination(len(list), k, seq)
def get_next_combination(num_elements, k, seq):
index_to_move = find_index_to_move(num_elements, seq)
if index_to_move == None:
return None
else:
seq[index_to_move] += 1
#for every element past this sequence, move it down
for i, elem in enumerate(seq[(index_to_move+1):]):
seq[i + 1 + index_to_move] = seq[index_to_move] + i + 1
return seq
def find_index_to_move(num_elements, seq):
"""Tells which index should be moved"""
for rev_index, elem in enumerate(reversed(seq)):
if elem < (num_elements - rev_index - 1):
return len(seq) - rev_index - 1
return None
Я создал решение в SQL Server 2005 для этого и разместил его на своем веб-сайте: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql .htm
Вот пример, демонстрирующий использование:
SELECT * FROM dbo.fn_GetMChooseNCombos('ABCD', 2, '')
результаты:
Word
----
AB
AC
AD
BC
BD
CD
(6 row(s) affected)
В C ++ следующая процедура будет производить все комбинации длины расстояние (first, k) между диапазоном [first, last):
#include <algorithm>
template <typename Iterator>
bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
/* Credits: Mark Nelson http://marknelson.us */
if ((first == last) || (first == k) || (last == k))
return false;
Iterator i1 = first;
Iterator i2 = last;
++i1;
if (last == i1)
return false;
i1 = last;
--i1;
i1 = k;
--i2;
while (first != i1)
{
if (*--i1 < *i2)
{
Iterator j = k;
while (!(*i1 < *j)) ++j;
std::iter_swap(i1,j);
++i1;
++j;
i2 = k;
std::rotate(i1,j,last);
while (last != j)
{
++j;
++i2;
}
std::rotate(k,i2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
Его можно использовать следующим образом:
#include <string>
#include <iostream>
int main()
{
std::string s = "12345";
std::size_t comb_size = 3;
do
{
std::cout << std::string(s.begin(), s.begin() + comb_size) << std::endl;
} while (next_combination(s.begin(), s.begin() + comb_size, s.end()));
return 0;
}
Это напечатает следующее:
123
124
125
134
135
145
234
235
245
345
В C #:
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) =>
elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] {e}).Concat(c)));
}
Использование:
var result = Combinations(new[] { 1, 2, 3, 4, 5 }, 3);
Результат:
123
124
125
134
135
145
234
235
245
345
Вот код, который я недавно написал на Java, который вычисляет и возвращает все комбинации элементов "num" из элементов "outOf" .
// author: Sourabh Bhat (heySourabh@gmail.com)
public class Testing
{
public static void main(String[] args)
{
// Test case num = 5, outOf = 8.
int num = 5;
int outOf = 8;
int[][] combinations = getCombinations(num, outOf);
for (int i = 0; i < combinations.length; i++)
{
for (int j = 0; j < combinations[i].length; j++)
{
System.out.print(combinations[i][j] + " ");
}
System.out.println();
}
}
private static int[][] getCombinations(int num, int outOf)
{
int possibilities = get_nCr(outOf, num);
int[][] combinations = new int[possibilities][num];
int arrayPointer = 0;
int[] counter = new int[num];
for (int i = 0; i < num; i++)
{
counter[i] = i;
}
breakLoop: while (true)
{
// Initializing part
for (int i = 1; i < num; i++)
{
if (counter[i] >= outOf - (num - 1 - i))
counter[i] = counter[i - 1] + 1;
}
// Testing part
for (int i = 0; i < num; i++)
{
if (counter[i] < outOf)
{
continue;
} else
{
break breakLoop;
}
}
// Innermost part
combinations[arrayPointer] = counter.clone();
arrayPointer++;
// Incrementing part
counter[num - 1]++;
for (int i = num - 1; i >= 1; i--)
{
if (counter[i] >= outOf - (num - 1 - i))
counter[i - 1]++;
}
}
return combinations;
}
private static int get_nCr(int n, int r)
{
if(r > n)
{
throw new ArithmeticException("r is greater then n");
}
long numerator = 1;
long denominator = 1;
for (int i = n; i >= r + 1; i--)
{
numerator *= i;
}
for (int i = 2; i <= n - r; i++)
{
denominator *= i;
}
return (int) (numerator / denominator);
}
}
Вот элегантная, универсальная реализация на Scala, описанная в 99 Scala Problems.
object P26 {
def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => Nil
case sublist@(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
}
def combinations[A](n: Int, ls: List[A]): List[List[A]] =
if (n == 0) List(Nil)
else flatMapSublists(ls) { sl =>
combinations(n - 1, sl.tail) map {sl.head :: _}
}
}
Могу я представить свое рекурсивное решение этой проблемы с помощью Python?
def choose_iter(elements, length):
for i in xrange(len(elements)):
if length == 1:
yield (elements[i],)
else:
for next in choose_iter(elements[i+1:len(elements)], length-1):
yield (elements[i],) + next
def choose(l, k):
return list(choose_iter(l, k))
Пример использования:
>>> len(list(choose_iter("abcdefgh",3)))
56
Мне нравится простота.
Вот простой код, который печатает все комбинации C (n, m). Он работает путем инициализации и перемещения набора индексов массива, указывающих на следующую допустимую комбинацию. Индексы инициализируются так, чтобы указывать на наименьшие m индексов (лексикографически наименьшую комбинацию). Затем, начиная с m-го индекса, мы пытаемся продвинуть индексы вперед. если индекс достиг своего предела, мы пробуем предыдущий индекс (вплоть до индекса 1). Если мы можем переместить индекс вперед, мы сбрасываем все большие индексы.
m=(rand()%n)+1; // m will vary from 1 to n
for (i=0;i<n;i++) a[i]=i+1;
// we want to print all possible C(n,m) combinations of selecting m objects out of n
printf("Printing C(%d,%d) possible combinations ...\n", n,m);
// This is an adhoc algo that keeps m pointers to the next valid combination
for (i=0;i<m;i++) p[i]=i; // the p[.] contain indices to the a vector whose elements constitute next combination
done=false;
while (!done)
{
// print combination
for (i=0;i<m;i++) printf("%2d ", a[p[i]]);
printf("\n");
// update combination
// method: start with p[m-1]. try to increment it. if it is already at the end, then try moving p[m-2] ahead.
// if this is possible, then reset p[m-1] to 1 more than (the new) p[m-2].
// if p[m-2] can not also be moved, then try p[m-3]. move that ahead. then reset p[m-2] and p[m-1].
// repeat all the way down to p[0]. if p[0] can not also be moved, then we have generated all combinations.
j=m-1;
i=1;
move_found=false;
while ((j>=0) && !move_found)
{
if (p[j]<(n-i))
{
move_found=true;
p[j]++; // point p[j] to next index
for (k=j+1;k<m;k++)
{
p[k]=p[j]+(k-j);
}
}
else
{
j--;
i++;
}
}
if (!move_found) done=true;
}