Позвольте мне попытаться решить эту проблему с помощью Kotlin:
fun <T> List<T>.permutations(): List<List<T>> {
//escape case
if (this.isEmpty()) return emptyList()
if (this.size == 1) return listOf(this)
if (this.size == 2) return listOf(listOf(this.first(), this.last()), listOf(this.last(), this.first()))
//recursive case
return this.flatMap { lastItem ->
this.minus(lastItem).permutations().map { it.plus(lastItem) }
}
}
Основная концепция: разбить длинный список на меньший список + рекурсия
Длинный ответ с примером списка [1, 2,3, 4]:
Даже для списка из 4 это уже немного сбивает с толку, пытаясь перечислить все возможные перестановки в вашей голове, и нам нужно именно этого избежать.Нам легко понять, как сделать все перестановки списка размером 0, 1 и 2, поэтому все, что нам нужно сделать, это разбить их на любой из этих размеров и правильно их объединить.Представьте себе машину с джекпотом: этот алгоритм начнет вращаться справа налево и запишет
- , возвращая пустое / список 1, когда размер списка равен 0 или 1
- , когдаразмер списка равен 2 (например, [3, 4]), и сгенерируйте 2 перестановки ([3, 4] и [4, 3])
- Для каждого элемента отметьте его как последний в последнем,и найти все перестановки для остальной части элемента в списке.(например, положить [4] на стол и снова перевести [1, 2, 3] в перестановку)
- Теперь, когда все перестановки являются дочерними, вернитесь к концу списка (например: [1, 2, 3] [, 4], [1, 3, 2] [, 4], [2, 3, 1] [, 4], ...)