解决重复元素全排列、组合问题

1.全排列

有重复元素的全排列

  1. 需要对元素进行排序
    然后再 全排列的时候加入
//重复元素  去重*************************
if(i>0&&a[i]==a[i-1]&&book[i-1]==0) continue;

例子: 对 一个数组{1,0,1,1} 进行全排列


import java.util.Arrays;

/**
 * 
 * @author sjf666
 * 
 * 2020年4月3日下午9:40:17
 */
public class Demo05_重复元素全排列 {
	
	    static int [] a= {1,0,1,1};
	    static int []ans = new int [a.length];
	    static int [] book = new int[a.length];
	    
	    public static void main(String[] args) {
	        Arrays.sort(a);
	    	dfs(0);
	    }

	    public static void dfs(int step){
	        if(step == ans.length)
	            System.out.println(Arrays.toString(ans));

	        for (int i = 0; i < a.length ; i++) {
	            if(i>0&&a[i]==a[i-1]&&book[i-1]==0) continue;
	            if(book[i] == 0){
	                book[i] = 1;
	                ans[step] = a[i];
	                dfs(step+1);
	                book[i] = 0;

	            }
	        }
	    }
}

好处: 此行if(i>0&&a[i]==a[i-1]&&book[i-1]==0) continue; 还可以筛掉很多次递归,可以优化程序, 在解决多个重复元素的全排列有很大的作用。


  1. 利用 HashSet集合去重(不考虑性能 可以使用 挺简单
    此方法只能对结果产生影响 ,不会对程序性能进行优化

例子:
组素数
素数就是不能再进行等分的数。比如:2 3 5 7 11 等。
9 = 3 * 3 说明它可以3等分,因而不是素数。
我们国家在1949年建国。如果只给你 1 9 4 9 这4个数字卡片,
可以随意摆放它们的先后顺序(但卡片不能倒着摆放啊,我们不是在脑筋急转弯!),那么,你能组成多少个4位的素数呢?
比如:1949,4919 都符合要求。
请你提交:能组成的4位素数的个数,不要罗列这些素数!!

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;

/**
 * 
 * @author sjf666
 * 
 * 2020年4月2日下午10:18:33
 */

// 全排列(有重复元素的) 检查素数
//重复元素  去重*************************
//if(i>0&&a[i]==a[i-1]&&book[i-1]==0) continue;
public class Demo04_组素数 {

	static int[] ans = new int [4];
	static int[] ku = new int [4];
	static int[] book = new int [4];
	static int count ;
	private static HashSet<String> set;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		set = new HashSet<String>();  //初始化集合
		for(int i = 0 ; i < 4 ; i++) {
		    ku[i] =sc.nextInt();
		}

		//Arrays.sort(ku);
		dfs(0);
		System.out.println(count);
		System.out.println(set.size());
//		for (Iterator iterator = set.iterator(); iterator.hasNext();) {
//			String string = (String) iterator.next();
//			System.out.println(string);
//		}
	}
	
	
	public static void dfs(int step) {
		if(step == 4) {
			if(check()) {
			   set.add(Arrays.toString(ans));
				count++;
			}
			return;
		}
		
		for (int i = 0; i < 4; i++) {
			//if(i>0&&ku[i]==ku[i-1]&&book[i-1]==0) continue;
			if(book[i] == 0) {
				ans[step] = ku[i];
				book[i] = 1;
				dfs(step+1);
				book[i] = 0;
			}
		}
	}
	
	public static boolean check() {
	
		int num = ans[0]*1000+ans[1]*100+ans[2]*10+ans[3];
		for(int i = 2 ; i <= Math.sqrt(num);i++) {
			if(num % i ==0)
				return false;
		}
		
		return true;
	}

}


2.组合问题

组合问题
是对每种元素的个数进行全部列举 只看元素在组合中所占的个数,不看顺序

以下代码是一个经典组合问题的求解

参数 step :指向每种元素 也可以看成盒子 只不过盒子中固定放的是一种元素 只是个数不一样
参数 goal :距离目标组合还有多少个元素可以添加

	/**
	 * 
	 * @param step  当前的位置    相当于在 data数组的下标 每个元素的指向
	 * @param goal  距离目标的剩余个数
	 * 
	 */
	public static void f(int step ,int goal) {
		
		if(step == ans.length ) {
			if(goal == 0)
				print();
			return;
		}
		
		//这里 i 的范围 应该是在 某种元素提供的个数 和 目标组合所需的个数中 去较小的那个
		for(int i = 0 ; i <= Math.min(data[step], goal); i++) {
			ans[step] = i;
			f(step+1, goal-i);
		}
		
	}

  1. X星球要派出一个5人组成的观察团前往W星。
    其中:
    A国最多可以派出4人。
    B国最多可以派出2人。
    C国最多可以派出2人。
    D国最多可以派出1人。
    E国最多可以派出1人。
    F国最多可以派出3人。
    那么最终派往W星的观察团会有多少种国别的不同组合呢?

    请输出所有不同的组合。


/**
 * 
 * @author sjf666
 * 
 * 2020年4月3日下午1:50:23
 */


public class Demo03_代表团出访 {

	static int[] data = {4,2,2,1,1,3};  //元素个数
	static int[] ans = new int[data.length];
	public static void main(String[] args) {
		 
		f(0, 5);
	
	}

	/**
	 * 
	 * @param step  当前的位置    相当于在 data数组的下标 每个元素的指向
	 * @param goal  距离目标的剩余个数
	 * 
	 */
	public static void f(int step ,int goal) {
		
		if(step == ans.length ) {
			if(goal == 0)
				print();
			return;
		}
		
		for(int i = 0 ; i <= Math.min(data[step], goal); i++) {
			ans[step] = i;
			f(step+1, goal-i);
		}
		
	}
	
	public static void print() {
		
		for(int i = 0; i < ans.length; i++)
			for(int j = 0; j<ans[i]; j++)
				System.out.print((char)('A'+i));
		System.out.println();
	}
}


  1. 扑克序列
    小明被劫持到X赌城,被迫与其他3人玩牌。
    一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
    这时,小明脑子里突然冒出一个问题:
    如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

/**
 * 
 * @author sjf666
 * 
 * 2020年4月3日下午2:12:51
 */


public class Demo04_组合_扑克序列 {

	static int[] data = {4,4,4,4,4,4,4,4,4,4,4,4,4};
	static int count ;
	static int[] ans = new int [data.length];
	public static void main(String[] args) {
		
		f(0, 13);
		System.out.println(count);
	}
	
	/**
	 * 
	 * @param step
	 * @param goal
	 */
	public static void f(int step ,int goal) {
		if(step == ans.length) {
			if(goal == 0)
				count++;
			return;
		}
			
		for(int i = 0; i <= Math.min(data[step], goal); i++ ) {
			ans[step] = i;
			f(step + 1 , goal - i);
		}
				
	}
	

		
}

发布了16 篇原创文章 · 获赞 94 · 访问量 4493

猜你喜欢

转载自blog.csdn.net/qq_45756224/article/details/105301736
今日推荐