next_permutation()函数(prev_permulation、is_permutation)

@TOC

总论

next_permutation、prev_permutation以及is_permutation均为全排列相关的函数,调用时需要加入头文件
#include < algorithm >

引入

next_permutation()

STL提供求下一个排列组合的函数next_permutation()。
next_permutation()函数是按照字典序产生排列的,并且是从数组中当前的字典序开始依次增大直至到最大字典序。
当已经是最后一次全排列的时候,函数会把传入的参数前后掉个个儿。

字符串的内部字典序排列(模仿):
bool next_str(string& str) {
	const int len = str.length();
	if (len <= 1) return false;

	int left = -1, right = -1;
	// 从后往前,找到第一个降序位置 left, 如 "2431" 中的位置 0,即 '2'
	for (int i = len - 1; i > 0; --i)
		if (str[i] > str[i - 1])
		{
			left = i - 1;
			break;
		}

	// 如果没有找到,则已经是最后一个 permutation,返回 false
	if (left == -1) return false;

	// 从后往前,找到第一个比 str[left] 大的位置 right, 如 "2431" 中的位置 2, 即 '3'
	for (int i = len - 1; i > left; --i)
		if (str[i] > str[left])
		{
			right = i;
			break;
		}

	// 交换 left 和 right
	swap(str[left], str[right]);

	// 从 left + 1 到最后,排序
	sort(str.begin() + left + 1, str.end());

	return true;
}

内部流程:

因为当完全降序的时候,直接返回 false,所以最后 str 保持完全降序结果。算法流程就是:
1、从后往前,找到第一个降序位置 left, 如 “2431” 中的位置 0,即 ‘2’
 (如果没有找到,则已经是最后一个 permutation,返回 false)
2、从后往前,找到第一个比 str[left] 大的位置 right, 如 “2431” 中的位置 2, 即 ‘3’
3、交换 left 和 right 位置上的值
4、从 left + 1 到最后,排序
  通过例子可以更好地理解:2431 -> 3124 -> 3142 。
  计算 2431 的下一个排列的过程为:
1、从后往前,找到第一个将序位置,即 ‘2’ 的位置 0
2、从后往前,找到第一个比 ‘2’ 大的值 ‘3’ 的位置 2
3、交换 ‘2’ 和 ‘3’, 变成 3421
4、从位置 1 (0 + 1) 到最后,进行排序,变成 3124,即为结果。

函数原型:
 template <class BidirectionalIterator>
 bool next_permutation (BidirectionalIterator first, BidirectionalIterator last );
 template <class BidirectionalIterator, class Compare>
 bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp );

在使用next_permutation函数的时候切记要对全排列的对象进行升序排列,不然结果只会出现比当前排列大的排列,依据ASCII计算。

next_permutation()的一个实现
template<class BidirectionalIterator, class Compare>
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp)
{
  BidirectionalIterator front = last - 1;
  BidirectionalIterator rear = last - 1;
  bool found = false;
  BidirectionalIterator i;
  while (!found && front > first)
  {
    i = rear; 
    front--;
    while(i>front)
    {
      if (comp(*front, *i))
      {
        found = true;
        break;
      }
      else
        i--;
     }
   }
   if (found)
   {
     swap(*i, *front);
     reverse(front + 1, last);
     return true;
  }
  else
  {
    reverse(first, last);
    return false;
  }
}
int main()
{ 
  string str = "1234";
  int i = 1;
  cout << i << ":" << str << endl;
  while (next_permutation(str.begin(), str.end(), less<char>()))
  {
    i++;
    cout << i << ":" << str << endl;
  }
}

对于数字的排列:

next_permutation(a, b)表示只对[a, b)区间的数据进行全排列,其余位置不变化
需要先找到最小和最大值的引用。(所以下面我先sort()了一下)

#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
    int n,a[1000];
    cin >> n;
    for(int i = 0 ; i < n ; i++)
        cin >> a[i];
    sort(a,a + n);
    do{
        for(int i = 0 ; i < n ; i++)
            cout << a[i] << " ";
        cout << endl;
    }while(next_permutation(a, a + n));
    return 0;
}


prev_permutation

prev_permutation和next_permutation功能一样,唯一的区别是next_permutation下一个全排列,而prev_permutation是上一个全排列,所以运用prev_permutation的时候必须降序排列,不然只会出现比结果小的排列.

is_permutation

is_permutation用来判断两个全排列是否相等,哪怕顺序不同,只要元素一样就返回true。
函数原型:

template <class ForwardIterator1, class ForwardIterator2>
   bool is_permutation (ForwardIterator1 first1, ForwardIterator1 last1,
                        ForwardIterator2 first2);
                        
template <class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
   bool is_permutation (ForwardIterator1 first1, ForwardIterator1 last1,
                        ForwardIterator2 first2, BinaryPredicate pred);

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
	vector<int> V1 = { 3, 4, 2, 1 };
	vector<int> V2 = { 1, 3, 2, 4 };
	vector<int> V3 = { 1, 3, 2, 4, 1};
	vector<float> V4 = { 1.0, 3.0, 2.0, 4.0 };
	vector<float> V5 = { 1.0000001, 3.0, 2.0, 4.0 };
	if (is_permutation(V1.begin(), V1.end(), V2.begin()))
	{
		cout << "V1 and V2 is equal" << endl;
	}
	if (is_permutation(V1.begin(), V1.end(), V3.begin()))
	{
		cout << "V1 and V3 is equal" << endl;
	}
	if (is_permutation(V1.begin(), V1.end(), V4.begin()))
	{
		cout << "V1 and V4 is equal" << endl;
	}
	if (is_permutation(V1.begin(), V1.end(), V5.begin()))
	{
		cout << "V1 and V5 is equal" << endl;
	}
	return 0;
}

//result
/*
V1 and V2 is equal
V1 and V3 is equal
V1 and V4 is equal
*/

题目1:Ignatius and the Princess II

添加链接描述

题目2:排列2

添加链接描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值