全排列的java实现(无重复元素)

题目原型:

Given a collection of numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:
[1,2,3][1,3,2][2,1,3][2,3,1][3,1,2], and [3,2,1].

基本思路:

(1).递归解法:

给定一个字符串,求出这些字符的全排列。面对这种复杂的问题,我们分解成小得问题来考虑。比如,面对一个字符串,我们把它分成两个部分:第一部分是它的第一个字符,第二部分是后面剩下的所有字符。那么我们要求字符串的全排列,可以分成两步:

1,首先求出所有可能在第一个位置出现的字符(可以把第一个字符和后面的所有的字符交换所得)。

2,确定了第一个字符以后,再对后面的所有字符进行全排列。(对剩下的字符全排列就相当于一个递归的过程,又从第一步开始处理)

因为给的集合,元素可能是无序的,所以首先进行排序,在这里使用快排:

	// 快速排序
	public void sort(int[] num,int low , int high)
	{
		int pivot = -1;
		if(low<high)
		{
			pivot = partition(low, high, num);
			sort(num, low, pivot-1);
			sort(num, pivot+1, high);
		}
			
	}
	public int partition(int low, int high, int[] num)
	{
		int reference = num[low];
		
		while(low<high)
		{
			while(low<high&&num[high]>=reference)
				high--;
			num[low] = num[high];
			while(low<high&&num[low]<=reference)
				low++;
			num[high] = num[low];
		}
		num[low] = reference;
		return low;
	}

然后递归求序列:

	ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();//全局变量
	//recursion全排列的递归实现(没有重复数字)
	public ArrayList<ArrayList<Integer>> permuteByRecursion(int[] num)
	{
		//排序
		sort(num, 0, num.length-1);
		allRange(num, 0, num.length-1);
		return result;
	}
	//添加
	public ArrayList<ArrayList<Integer>> add(ArrayList<ArrayList<Integer>> result,int[] num)
	{
		ArrayList<Integer> in = new ArrayList<Integer>();
		for(int i = 0;i<num.length;i++)
		{
			in.add(num[i]);
		}
		result.add(in);
		return result;
	}
	//sur表示当前选取的数,sum表示总共有多少个数
	public void allRange(int[] num,int cur,int sum)
	{
		if(cur==sum)
		{
			//添加result
			add(result, num);
			return;
		}
		else
		{
			for(int i = cur;i<=sum;i++)//第i个数分别与它后面的数字交换就能得到新的排列
			{
				swap(num, i, cur);
				allRange(num, cur+1, sum);//表示,若sur和sum相邻时输出
				swap(num, i, cur);
			}
		}
	}
	//交换
	public void swap(int[] num ,int i , int j)
	{
		int temp = num[i];
		num[i] = num[j];
		num[j] = temp;
	}

(2)非递归解法

要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。

如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符串"6220"颠倒即得到"950226"。

	//全排列的(非递归实现)
	public ArrayList<ArrayList<Integer>> permute(int[] num)
	{
		// 排序num中的数,简便起见,采用快速排序
		sort(num, 0, num.length-1);
		
		for(int i = 0; i < num.length; i++)
			System.out.print(num[i]);
		
		System.out.println("********************************");
		ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
		// 第一个数
		ArrayList<Integer> number = new ArrayList<Integer>();
		for (int i = 0; i < num.length; i++)
		{
			number.add(num[i]);
		}
		result.add(number);
		boolean hasFound = true;
		int i, j;
		while (hasFound)
		{
			hasFound = false;
			// 从后往前找到两个相邻的升序序列,前一个数为替换数
			for (i = num.length - 1; i > 0; i--)
			{
				if (num[i - 1] < num[i])
				{
					hasFound = true;
					break;
				}
			}
			if (hasFound == false)
				break;
			number = new ArrayList<Integer>();
			// 从后往前走,找到第一个比替换书大的数
			for (j = num.length - 1; j > i - 1; j--)
			{
				if (num[j] > num[i - 1])
				{
					int temp = num[i - 1];
					num[i - 1] = num[j];
					num[j] = temp;
					break;
				}
			}
			// 倒置替换数后面的数
			for (j = num.length - 1; i < num.length - 1 && j > i; i++, j--)
			{
				int temp = num[i];
				num[i] = num[j];
				num[j] = temp;
			}
			for (i = 0; i < num.length; i++)
				number.add(num[i]);
			result.add(number);
		}
		return result;
	}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值