打印出大小为n的数组(可能有重复元素)里所有可能的组合

Input:

{1, 2, 3, 4}, r=2

Output:

{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4} and {3, 4}.



package recursion;

import java.util.ArrayList;
import java.util.Collections;

public class Print_all_possible_combinations_of_r_elements_in_a_given_array_of_size_n {

	/*
	 Input:
	 {1, 2, 3, 4}, r=2
	 Output:
	 {1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4} and {3, 4}.
	 
	 */
	public static void main(String[] args) {
		int[] s1 = {1, 2, 3, 4};
		ArrayList<Integer> set1 = new ArrayList<Integer>();
		for (int i : s1) {
			set1.add(i);
		}
		int r1 = 2;
		ArrayList<ArrayList<Integer>> ret1 = new ArrayList<ArrayList<Integer>>();
		rec2(set1, r1, 0, ret1, new ArrayList<Integer>());
		System.out.println(ret1);

		int[] s2 = {1, 2, 1, 3, 2};
		ArrayList<Integer> set2 = new ArrayList<Integer>();
		for (int i : s2) {
			set2.add(i);
		}
		int r2 = 2;
		ArrayList<ArrayList<Integer>> ret2 = new ArrayList<ArrayList<Integer>>();
		
		Collections.sort(set2);
		rec2(set2, r2, 0, ret2, new ArrayList<Integer>());
		System.out.println(ret2);
	}
	
	// 解法一:分析:观察output可得,先循环选定添加到al的第一个元素,然后缩小子区间,递归处理子问题
	// first是当前处理子区间的第一个元素
	public static void rec(ArrayList<Integer> set, int r, int first, ArrayList<ArrayList<Integer>> ret, ArrayList<Integer> al) {
		if(al.size() == r) {			// 退出条件:当al里的数量达到r时即可退出
			ret.add(new ArrayList<Integer>(al));
			return;
		}
		
		for(int i=first; i<set.size(); i++) {		// 从子区间的第一个元素到最后一个元素都有机会被添加到al中 
			if(i+1<set.size() && set.get(i+1) == set.get(i)) {		// 跳过重复元素,但要检查是否越界
				continue;
			}
			al.add(set.get(i));				// 注意在for循环内,用到的参数是i而不是first
			rec(set, r, i+1, ret, al);		// 缩短子区间1个距离
			al.remove(al.size()-1);
		}
	}
	
	// 解法二:选择或者不选择某个元素
	public static void rec2(ArrayList<Integer> set, int r, int first, ArrayList<ArrayList<Integer>> ret, ArrayList<Integer> al) {
		if(r == al.size()) {			// 退出条件:当al里的数量达到r时即可退出
			ret.add(new ArrayList<Integer>(al));
			return;
		}
		
		if(first >= set.size()) {		// 当first遍历超过set容量时也要返回
			return;
		}
		
		while(first+1<set.size() && set.get(first+1) == set.get(first)) {		// 跳过重复元素,但要检查是否越界
			first++;
		}
		
		rec2(set, r, first+1, ret, al);	// 不选择当前元素
		
		
		al.add(set.get(first));			// 选择当前元素
		rec2(set, r, first+1, ret, al);
		al.remove(al.size()-1);
	}
	
}




http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值