Algorithm,permutation,next_permutation,算法,下一个排列
#include <iostream> bool next_permutation(int *arr, int n) { if (n == 1 || n == 0) return false; int i; for (i = n - 2; i >= 0; --i) { if (arr[i] < arr[i + 1]) break; } if (i == -1) return false; else { int j; for (j = n -1; ; --j) { if (arr[j] > arr[i]) break; } int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } int low = i + 1; int high = n - 1; for( ; low < high; ++low, --high) { int tmp = arr[low]; arr[low] = arr[high]; arr[high] = tmp; } return true; } int main() { int arr[] = {1, 2, 3, 4, 5}; while (1) { for (unsigned i = 0; i < sizeof(arr)/sizeof(*arr); ++i) std::cout << arr[i] << " "; std::cout << std::endl; if (!next_permutation(arr, sizeof(arr)/sizeof(*arr))) break; } return 0; }
这个算法本质上是贪心的,由上一个字典序生成下一个字典序
贪心找后面可以变动的序列:
1. 从后到前,找第一正序对 使: arr[i] < arr[i + 1] > arr[i + 2] > arr[i + 3] > ...
意味着只需要更改[i, n -1]的序列,可实现现有序列字典序的最小增长
我们看到[i + 1, n - 1]序列已经达到最大值,这个序列中至少存在一个值 大于 arr[i]
注意 [0 , i - 1] 的数不能动,因为变动那些不可能是字典序的最小增长, 所以只能从后面选一个数arr[j],替换i位置,贪心选择最小的数
在[i + 1, n - 1]中从后向前找到第一个大于 arr[i]的 arr[j], 令 arr[i] 与 arr[j] 交换.
交换后,i 位置数已经正确,[i + 1, n - 1],是排列的最大序, 对其逆序即可
:如
0 1 2 3 4 5 6
4 1 3 < 7 > 6 > 5 > 2 index i = 2 j = 5
交换
4 1 5 7 > 6 > 3 > 2
逆序
4 1 5 2 3 6 7