排列和組合在數學上特別的常見,同時,在編程比賽當中也會經常碰到。STL封裝了特別高效的排列組合函數:next_permutation和pre_permutation,理解它們實現的思想,才能更好地運用。
1.next_permutation
實現思想:首先,從最尾端開始往前尋找兩個相鄰元素,令第一元素爲*i,第二元素爲*ii,且滿足*i < *ii,找到這樣一組相鄰元素後,再從最尾端開始往前檢驗,找出第一個大於*i的元素,令爲*j,將i,j元素對調,在將ii之後的所有元素顛倒。
具體實現:
template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first,
BidirectionalIterator last) {
if (first == last) return false; //空數組
BidirectionalIterator i = first;
++i;
if (i == last) return false; //只有一個元素
i = last;
--i;
for(;;) {
BidirectionalIterator ii = i;
--i;
if (*i < *ii) { //查找一對相鄰的元素,且*i < *ii
BidirectionalIterator j = last;
while (!(*i < *--j)); //從最尾端開始,查找第一個大於*i的數
iter_swap(i, j); //交換*j和*i
reverse(ii, last); //將迭代器[first, last]範圍內的數據顛倒
return true;
}
if (i == first) { //進行到最前面
reverse(first, last); //重新開始排
return false;
}
}
}
template <class BidirectionalIterator>
inline void reverse(BidirectionalIterator first, BidirectionalIterator last) {
__reverse(first, last, iterator_category(first));
}
template <class RandomAccessIterator>
void __reverse(RandomAccessIterator first, RandomAccessIterator last,
random_access_iterator_tag) {
while (first < last) iter_swap(first++, --last); //將迭代器[first, last]範圍內的數據顛倒
}
2.pre_permutation
實現思想:首先,從最尾端開始往前尋找兩個相鄰元素,令第一元素爲*i,第二元素爲*ii,且滿足*i > *ii,找到這樣一組相鄰元素後,再從最尾端開始往前檢驗,找出第一個小於*i的元素,令爲*j,將i,j元素對調,在將ii之後的所有元素顛倒。
具體實現:
template <class BidirectionalIterator>
bool prev_permutation(BidirectionalIterator first,
BidirectionalIterator last) {
if (first == last) return false; //空數組
BidirectionalIterator i = first;
++i;
if (i == last) return false; //只有一個元素
i = last;
--i;
for(;;) {
BidirectionalIterator ii = i;
--i;
if (*ii < *i) { //查找一組相鄰的元素,且*i > *ii
BidirectionalIterator j = last;
while (!(*--j < *i)); //從最尾端開始,查找第一個小於*i的數
iter_swap(i, j); //交換
reverse(ii, last); //將迭代器[first, last]範圍內的數據顛倒
return true;
}
if (i == first) { //進行到最前面
reverse(first, last); //從頭開始排
return false;
}
}
}
template <class BidirectionalIterator>
inline void reverse(BidirectionalIterator first, BidirectionalIterator last) {
__reverse(first, last, iterator_category(first));
}
template <class RandomAccessIterator>
void __reverse(RandomAccessIterator first, RandomAccessIterator last,
random_access_iterator_tag) {
while (first < last) iter_swap(first++, --last); //將迭代器[first, last]範圍內的數據顛倒
}
3.具體運用
https://leetcode.com/problems/next-greater-element-iii/
1.《STL庫源碼解析》------侯捷
2.《STL3.0》源碼