求序列的全排列

题目:给定一个序列,求出其全排列,并保证有序。例如字符串123的全排列是123,132,213,231,312,321。


解答:

  1. 递归解法。从第一个数开始的每一个数字与其后面的数字交换。如果序列中存在重复数据,比如122,则在交换之前看两个交换数字之间有没有与下标比较大的交换数字相等的数字,如果有的话,则不交换。比如122中,1与第二个2交换,发现中间有一个2,所以不交换,因为它们即使交换,得到的排列是221,但是1与第一个2交换得到了212可以进一步通过交换获得221.
  2. 非递归解法,使用字典序算法。基本思路是:
  • 对于输入的字典许排列<a1,a2,…,an>,反向查找第一对满足a[j]<a[j+1]的下标j
  • 仍旧反向查找一个下标k,使得 a[j]<a[k]并且a[k]=min{a[t] | any t, a[j]<a[t]}
  • 交换a[j]和a[k]
  • 反转a[j+1..n]  

代码:

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

//防止产生重复排列
bool canSwap(char *arr, int begin, int end)
{
	char v = arr[end];
	for(int i = begin; i < end; i++)
	{
		if(arr[i] == v)
			return false;
	}
	return true;
}

//递归解法
void AllRange(char *arr, int k, int m)
{
	if(k == m)
	{
		printf("%s\n", arr);
	}
	else
	{
		for(int i = k; i <= m; i++)
		{
			if(canSwap(arr, k, i))
			{
				swap(arr[k], arr[i]);
				AllRange(arr, k + 1, m);
				swap(arr[k], arr[i]);
			}
		}
	}
}

//非递归解法,字典序算法
bool getNext(char *arr, int n)
{
	if(arr == NULL || n <= 1)
		return false;
	int j = n - 2;
	while(j >= 0 && arr[j] >= arr[j + 1])
	{
		j--;
	}
	if(j < 0)
		return false;

	int i = n - 1;
	while(arr[j] >= arr[i] && i > j)
	{
		i--;
	}

	swap(arr[i], arr[j]);
	while(j + 1 < n - 1)
	{
		swap(arr[j + 1], arr[n - 1]);
		j++;
		n--;
	}
	return true;
}

//测试
int main()
{
	//char arr[4] = "111";
	//char arr[4] = "123";
	//char arr[4] = "122";
	char arr[4] = "321";
	cout << "递归结果:" << endl;
	AllRange(arr, 0, 2);

	cout << "非递归结果:" << endl;
	sort(arr, arr + 3);
	cout << arr << endl;
	while(getNext(arr, 3))
	{
		cout << arr << endl;
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值