对一组数排列,包含相同元素

本文探讨了在特定约束条件下(如7不位于第二位、6和8不相邻)对一组包含重复元素的数字进行全排列的问题。通过两种不同的算法实现——一种基于递归生成所有可能的排列并去除不符合条件的情况;另一种则是通过数值范围限定直接筛选出有效排列。对比了两者的效率差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:{3,2,2,6,7,8}排序输出,7不在第二位,68不在一起。

 

 

分析思考:

 

1.编写输出全部元素的排序组合,6位数共有6!个排序方式,即720个

 

2.由于有两个2,即重复元素,则最终将会有重复的排序方式,输出的个数720/2! = 360个,再去掉与7和68的限制相关的组合

 

 

全部元素排序

第一个位置有6种情况,取一个数放在第一位上,则第二位剩下5个元素,依次递归到最后一个元素,则得出一个排列组合。

按此方法,将全部排列输出

/**
	 * 分组排序
	 * @param source
	 */
	public static void group(int source[]) {
		for (int i = 0; i < source.length; i++) {

			int[] target = new int[source.length];

			// 第一个数有source.length种情况
			int first = source[i];

			int sourceStart = 0;
			target[sourceStart] = first;

			//通过下标移除已经选择的元素
			int[] leaveCollection = removeSelectIndex(i, source);
			groupNext(leaveCollection, sourceStart + 1, target,source.length);
		}
	}
	
	/**
	 * 通过下标移除已经选择的元素
	 * @param index
	 * @param source
	 * @return
	 */
	static int[] removeSelectIndex(int index , int[] source){
		int [] leaveCollection = new int[source.length -1];
		int leaveIndex = 0;
		for(int i = 0 ;i < source.length ;i++){
			if(index != i){
				leaveCollection[leaveIndex++] = source[i];
			}
		}
		return leaveCollection;
	}
	
	/**
	 * 第二个数有剩余source.length-1 种情况,第三个数从剩余中取,source.length-2种情况
	 * 
	 * @param source
	 * @param sourceStart
	 * @param target
	 */
	static void groupNext(int[] nextCollection, int sourceStart, int[] target,int sourceLength) {
		for (int l = 0; l < nextCollection.length; l++) {
			int second = nextCollection[l];

			target[sourceStart] = second;

			if (sourceStart + 1 < sourceLength) {
				// 递归下一位
				int[] copyOf = Arrays.copyOf(target, target.length);
				
				int[] source = removeSelectIndex(l, nextCollection);
				groupNext(source, sourceStart + 1, copyOf,sourceLength);
			} else {
				// 循环结束,输出结果
				println(target);
			}
		}
	}

 

由于有重复元素,在取剩下需要排序的集合时,不能用值去集合中删除,如在{22678}中删除2的元素,则剩下{678},通过下标移除是最好的方法。

 

 

删除不符合题意的组合

1.println(target)中,自行将7和68的限制去掉

 

2.由于有22存在,则在720个排列当中,有一半是重复的。需要把这些数据删除。最简单的做法通过Map,往Map中put进相同的元素,达到去重效果。

	static void println(int target[]) {
		StringBuffer bf = new StringBuffer();
		for (int i : target) {
			bf.append(i);
		}

		String value = bf.toString();
		
		if (value.indexOf("7") == 1)// except 7 in second position
			return;

		if (value.indexOf("68") != -1 || value.indexOf("86") != -1)// except adjoining
			return;

		rs.put(value, value);
	}

 

 

算法分析

 

解法二:

这种排序做法很早就看到过,通过将元素拼成两个数,再依次递增。判断输出结果:

 

public static void sort(String[] args) {
		// {3,2,2,6,7,8},其中7不能放在第二个位置,6和8不能相邻,打印所有的排列

		List<String> list = new ArrayList<String>();
		for (int i = 223678; i <= 876322; i++)
			list.add(i + "");

		int size = 0;// all size

		for (String s : list) {
			if (s.indexOf("0") != -1 || s.indexOf("1") != -1
					|| s.indexOf("4") != -1 || s.indexOf("5") != -1
					|| s.indexOf("9") != -1)// except 0,1,4,5,9
				continue;

			if (s.indexOf("2") == -1 || s.indexOf("3") == -1
					|| s.indexOf("6") == -1 || s.indexOf("7") == -1
					|| s.indexOf("8") == -1
					|| s.indexOf("2", s.indexOf("2") + 1) == -1)// contain all
				// 3,2,2,6,7,8
				continue;

			if (s.indexOf("7") == 1)// except 7 in second position
				continue;

			if (s.indexOf("68") != -1 || s.indexOf("86") != -1)// except
				// adjoining 6,8
				continue;
			size++;

			 System.out.println(s);
		}

		// System.out.println("All size --> " + size);// All size --> 198
	}

 

结果出来也是正确的。

 

但此算法循环的次数是876322-223678次=600000次,并且每次大约有10次的字符串indexOf操作,最终耗时500ms左右

 

而排序组合解法中,总共循环的次数为720次,耗时在15-50ms之间。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值