全排列问题(0907)

【问题】给出字符串或者一个数组的全排列,

例如"abc",那么所有的排列组合有"abc"、"acb"、"bac"、"bca"、"cba"、"cab",对数组也是如此。

【思路】递归

  1. 首先固定第一个字符,a,那么,以a开头的剩下的组合,就变成了"bc"的组合,有"bc"、"cb";
  2. 然后将原来字符串的第二个字符b与a交换,重复上一步的过程
  3. 然后将第三个字符c与原字符的a交换,重复第一步的过程
  4. 在第一步的过程中,其实是个递归过程,固定a,求剩下的全排列,然后在固定前两个字符,求剩下的字符的全排列,递归的边界就是未固定部分到了整个字符串的结束位置。
  5. OK,按照这个思路,递归函数有三个参数,首先是原字符串str,起始的固定位置k,终止位置m,固定0~k,全排列k+1~m-1;
【写法1】
void str_perm(char* str, int k, int m, int& count)
{
	assert(str != NULL && k <= m);
	if(k == m)
	{
		cout<<str<<endl;
		count++;
	}
		
	else
	{
		for (int i = k; i < m; i++)
		{
			swap(str[i], str[k]);
			str_perm(str, k+1, m, count);
			swap(str[i], str[k]);
		}
	}

}

【写法2】
//@2 第二种写法,主要是根据字符串的结束'\0'来处理
void str_permutation(char* str, char* begin)
{
	assert(str != NULL && begin != NULL);
	if(*begin == '\0')
		cout<<str<<endl;
	else
	{
		for (char* s = begin;*s != '\0'; ++s)
		{
			swap(*s, *begin);			
			str_permutation(str,begin+1);
			swap(*s, *begin);
		}	
	}
}

【对数组的处理】其实大同小异
//void perm(int *a, int k, int m)是将a[]的第0~k个元素不变,第k+1~m-1个元素进行全排列得到
void perm(int *a, int k, int m)
{

	if(k == m)
	{
		for (int i=0; i < m; i++)
			cout<<a[i]<<" ";
		cout<<endl;
	}		
	else
	{
		for (int i = k; i < m; i++)
		{
			swap(a[k], a[i]);
			perm(a, k+1, m);
			swap(a[k], a[i]);
		}		
	}
}

【测试代码】

#include <assert.h>
#include <iostream>
using namespace std;
int main()
{

	int a[]={1,2,3};
	perm(a, 0, 3);
	char s[]="your";
	int times = 0;
	str_perm(s, 0, strlen(s), times);
	str_permutation(s, s);
}

【体会】

递归是一个伟大的思想,每次看完用递归写的代码,总有这样的感叹!可以说,不会递归,就不是合格的程序员:),而递归的关键就是发现规律,让问题规模朝着小的方向,然后找到边界剩下的就是debug了!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值