求不重复数据的全排列

 学计算机这么久了还不会这个,有点说不过去。今天看了看。算法还是比较容易理解的。

比如,可以使用递归将问题切割为较小的单元进行排列组合,例如1 2 3 4的排列可以分为

1 [2 3 4] 、2 [1 3 4]、3 [1 2 4]、4 [1 2 3]进行排列,

这边利用旋转法,先将旋转间隔设为0,将最右边的数字旋转至最左边,并逐步增加旋转的间隔,例如: 

1 2 3 4 -> 旋转1 -> 继续将右边2 3 4进行递归处理

2 1 3 4 -> 旋转1 2 变为 2 1-> 继续将右边1 3 4进行递归处理

3 1 2 4 -> 旋转1 2 3变为 3 1 2 -> 继续将右边1 2 4进行递归处理

4 1 2 3 -> 旋转1 2 3 4变为4 1 2 3 -> 继续将右边1 2 3进行递归处理

代码如下:

public class test {
	public static void main(String args[]) {
		int[] cs = new int[5];
		for (int j = 0; j < cs.length; j++) {
			cs[j] = j + 1;
		}
		getPerm(cs, 0);
	}
	public static void getPerm(int[] cs, int i) {
		if (i < cs.length - 1) {
			for (int j = i; j < cs.length; j++) {
				int temp = cs[j];
				// 右移数据
				for (int k = j; k > i; k--)
					cs[k] = cs[k - 1];
				cs[i] = temp;
				getPerm(cs, i + 1);
				//每次都要把数据恢复之后才可以进行下一次排列
				for (int k = i; k < j; k++)
					cs[k] = cs[k + 1];
				cs[j] = temp;
			}
		} else {// 如果i是cs.length()-1的话,那么说明已经排列到最后一个元素,可以不用继续排列了,输出该数组既可以
			for (int m = 0; m < cs.length; m++)
				System.out.print(cs[m]);
			System.out.println();
		}
	}
}

如果要求按照大小输出的话,只需要在排序之前,对需要排序的数字进行排序。

--------------------------------------------------------魂歌----------------------------------------------------------

正式开始找工作了。不论找实习还是工作,都要复习一下算法。这次自己写了一下这个算法,还算写的不错吧,思路比较清晰。看来算法就是越用越熟练了。

package zoer;

import java.util.ArrayList;
import java.util.List;

public class CopyOfT {
	static int count = 0;

	public static void main(String args[]) {
		get("1234", new ArrayList<String>());
		System.out.println("全排列个数为:"+count);
	}

	public static void get(String s, List<String> list) {
		if (s.length() == 1) {
			count++;
			for (int i = 0; i < list.size(); i++) {
				System.out.print(list.get(i));
			}
			System.out.println(s);
		} else {
			for (int i = 0; i < s.length(); i++) {
				list.add("" + s.charAt(0));
				String sub = s.substring(1, s.length());
				get(sub, list);
				s = sub + s.charAt(0);
				list.remove(list.size() - 1);
			}
		}
	}
}

每次把下一个字符提到字符串的最前端,对剩余的字串做相同的操作。直到剩余的子字符串的长度为1的时候,输出得到的全排列结果。

上面的代码中,s = sub + s.charAt(0);的意思是说,第一个字符处理完毕之后,把它加到字符串的末尾,然后处理第二个字符。依次类推直到所有的字符都处理完毕【这里说的处理,具体就是指把一个字符摘出来,对其他剩余的字符串做全排列】。

------------------------------------------------------------------------------

上面的算法是对一个非重复字符串的全排列,但是没有按照原来的字符中字符顺序来输出,主要是因为在移动字符的时候,直接s = sub + s.charAt(0);这样的结果是第一个字符直接跑到最后去了。而不是跟相应的字符进行交换,那么按照下面的代码,即可实现按照”字符原来“的顺序进行输出。

package zoer;

import java.util.ArrayList;
import java.util.List;

public class CopyOfT {
	static int count = 0;

	public static void main(String args[]) {
		get("1234", new ArrayList<String>());
		System.out.println("全排列个数为:" + count);
	}

	public static void get(String s, List<String> list) {
		if (s.length() == 1) {
			count++;
			for (int i = 0; i < list.size(); i++) {
				System.out.print(list.get(i));
			}
			System.out.println(s);
		} else {
			for (int i = 0; i < s.length(); i++) {
				list.add("" + s.charAt(0));
				String sub = s.substring(1, s.length());
				get(sub, list);
				if (i != s.length() - 1) {
					s = s.charAt(i + 1) + s.substring(0, i + 1)
							+ s.substring(i + 2, s.length());
				}
				list.remove(list.size() - 1);
			}
		}
	}
}

不过上面的这个算法是求不重复字串的全排列。重复的还要再考虑下,,,

---------------------------------------------有重复的情况--------------------------------------------

这里考虑了有重复的情况。如果重复的字符在字符串中不是第一次出现,那么就不用递归这个字符了。用一个数组来记录每一个字符在字符串中第一次出现的位置。

实现代码如下:

package zoer;

import java.util.ArrayList;
import java.util.List;

public class CopyOfT {
	static int count = 0;

	public static void main(String args[]) {
		String s = "1223";
		get(s, new ArrayList<String>());
		System.out.println("全排列个数为:" + count);
	}

	public static void get(String s, List<String> list) {
		if (s.length() == 1) {
			count++;
			for (int i = 0; i < list.size(); i++) {
				System.out.print(list.get(i));
			}
			System.out.println(s);
		} else {
			int index[] = new int[s.length()];
			for (int i = 0; i < index.length; i++) {
				index[i] = s.indexOf(s.charAt(i));// 用index数组记录字符串中相应位置的字符在字符串中第一次出现的位置
			}
			for (int i = 0; i < s.length(); i++) {
				String sub = s.substring(1, s.length());
				// 如果一个数不在他第一次出现的位置,那么这个字符是重复的,跳过这个字符;否则才递归
				if (i == index[i]) {// 查看第i个字符在字符串中出现的位置是不是与i相同,如果不同,说明是重复的
					list.add("" + s.charAt(0));
					get(sub, list);
					list.remove(list.size() - 1);
				}
				s = sub + s.charAt(0);
			}
		}
	}
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值