打印和为sum的组合,动规法+DFS+迭代法

一.判断是否有和为sum的组合,动规法,O(n^2)

// 判断是否有和为n的组合,动规法,O(n^2)
public static boolean findSum(int[] a, int n) {
		boolean[] dp = new boolean[n + 1];
		for (int i = 0; i < a.length; i++) {
			if (a[i] > n) {
				continue;
			}
			for (int j = n; j >= a[i]; j--) {
				if (dp[j - a[i]]) {
					dp[j] = true;
				}
			}
			dp[a[i]] = true;
			if (dp[n]) {
				return true;
			}
		}
		return false;
	}

二、 有几种和为n的组合,动规法,O(n^2)

// 有几种和为n的组合,动规法,O(n^2)
	public static int findSum2(int[] a, int n) {
		int[] dp = new int[n + 1];
		dp[0] = 1;
		for (int i = 0; i < a.length; i++) {
			if (a[i] > n) {
				continue;
			}
			for (int j = n; j >= a[i]; j--) {
				if (dp[j - a[i]] > 0) {
					dp[j] += dp[j - a[i]];
				}
			}
			if (dp[a[i]] == 0) {
				dp[a[i]] = 1;
			}
		}
		return dp[n];
	}

 

三.查找和为sum的所有组合

 方法一:打印和为n的所有组合,DFS法,O(2^n)

// 查找和为n的所有组合,DFS法,O(2^n)
	public static void dfs(int current, int sum, int n, int[] questions, ArrayList<Integer> path,
			HashSet<List<Integer>> result) {
		if (sum == n) {
			result.add(new ArrayList<>(path));
			return;
		}
		if (sum > n) {
			return;
		}
		for (int i = current; i < questions.length; i++) {
			path.add(questions[i]);
			dfs(i + 1, sum + questions[i], n, questions, path, result);
			path.remove(path.size() - 1);
		}
	}

方法二:打印和为n的组合,动规法,O(n^2

// 打印和为n的组合,动规法,O(n^2)
	public static List<List<Object>> findSums(int[] a, int n) {
		boolean[] dp = new boolean[n + 1];
		List<List<Object>>[] list = new ArrayList[n + 1];
		for (int i = 0; i < list.length; i++) {
			list[i] = new ArrayList<>();
		}
		List<Object> temp = new ArrayList<>();
		for (int i = 0; i < a.length; i++) {
			if (a[i] > n) {
				continue;
			}
			for (int j = n; j >= a[i]; j--) {
				if (dp[j - a[i]]) {
					dp[j] = true;
					for (List<Object> arrayList : list[j - a[i]]) {
						temp = new ArrayList<>(arrayList);
						temp.add(a[i]);
						list[j].add(new ArrayList<>(temp));
					}
				}
			}
			dp[a[i]] = true;
			temp.clear();
			temp.add(a[i]);
			list[a[i]].add(new ArrayList<>(temp));
		}
		return list[n];
	}

方法三:打印和为n的组合,迭代法,<O(n*2^n)


	// 打印和为n的组合,迭代法,<O(n*2^n)
	public static List<List<Integer>> findSums(int[] a, int n) {
		List<List<Integer>> result = new ArrayList<>();
		int len = a.length;
		int bit = 1 << len;
		for (int i = 1; i < bit; i++)// 从1循环到2^N
		{
			int sum = 0;
			List<Integer> tmp = new ArrayList<>();
				for (int j = 0; j < len; j++) {
					if ((i & 1 << j) != 0)// 用i与2^j进行位与运算,若结果不为0,则表示第j位不为0,从数组中取出第j个数
					{
						sum += a[j];
						tmp.add(a[j]);
					}
				}
				if (sum == n) {
					result.add(tmp);
				}
		}
		return result;
	}

方法四:从长度为len的数组里选出m个数使和为固定值n,<O(n*2^n)


	// 从长度为len的数组里选出m个数使和为固定值n,<O(n*2^n)
	public static List<List<Integer>> CalSum(int[] a, int n, int m) {
		List<List<Integer>> result = new ArrayList<>();
		int len = a.length;
		int bit = 1 << len;
		for (int i = 1; i < bit; i++)// 从1循环到2^N
		{
			int sum = 0;
			List<Integer> tmp = new ArrayList<>();
			if (NumOf1(i) == m) {// 判断是否为每个数
				for (int j = 0; j < len; j++) {
					if ((i & 1 << j) != 0)// 用i与2^j进行位与运算,若结果不为0,则表示第j位不为0,从数组中取出第j个数
					{
						sum += a[j];
						tmp.add(a[j]);
					}
				}
				if (sum == n) {
					result.add(tmp);
				}
			}
		}
		return result;
	}

	public static int NumOf1(int num) {
		int count = 0;
		while (num > 0) {
			num = num & (num - 1);
			count++;
		}
		return count;
	}

测试主程序:

用例:

11
9 49 1 2 48 50 47 3 1 2 41

输出:


是否可以:true
动规不去重打印: 大小:37

有几种:37

[[1, 2, 9, 41, 47], [1, 2, 9, 41, 47], [1, 2, 9, 41, 47], [1, 2, 9, 41, 47], [3, 9, 41, 47], [1, 1, 9, 41, 48], [2, 9, 41, 48], [2, 9, 41, 48], [1, 2, 2, 47, 48], [1, 2, 2, 47, 48], [1, 1, 3, 47, 48], [2, 3, 47, 48], [2, 3, 47, 48], [1, 9, 41, 49], [1, 9, 41, 49], [1, 1, 2, 47, 49], [1, 1, 2, 47, 49], [2, 2, 47, 49], [1, 3, 47, 49], [1, 3, 47, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 48, 49], [3, 48, 49], [1, 1, 2, 2, 3, 41, 50], [9, 41, 50], [1, 2, 47, 50], [1, 2, 47, 50], [1, 2, 47, 50], [1, 2, 47, 50], [3, 47, 50], [1, 1, 48, 50], [2, 48, 50], [2, 48, 50], [1, 49, 50], [1, 49, 50]]

迭代不去重打印: 大小:37

[[1, 2, 9, 41, 47], [1, 2, 9, 41, 47], [1, 2, 9, 41, 47], [1, 2, 9, 41, 47], [3, 9, 41, 47], [1, 1, 9, 41, 48], [2, 9, 41, 48], [2, 9, 41, 48], [1, 2, 2, 47, 48], [1, 2, 2, 47, 48], [1, 1, 3, 47, 48], [2, 3, 47, 48], [2, 3, 47, 48], [1, 9, 41, 49], [1, 9, 41, 49], [1, 1, 2, 47, 49], [1, 1, 2, 47, 49], [2, 2, 47, 49], [1, 3, 47, 49], [1, 3, 47, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 48, 49], [3, 48, 49], [1, 1, 2, 2, 3, 41, 50], [9, 41, 50], [1, 2, 47, 50], [1, 2, 47, 50], [1, 2, 47, 50], [1, 2, 47, 50], [3, 47, 50], [1, 1, 48, 50], [2, 48, 50], [2, 48, 50], [1, 49, 50], [1, 49, 50]]


m个和为n:

[[3, 9, 41, 47], [2, 9, 41, 48], [2, 9, 41, 48], [2, 3, 47, 48], [2, 3, 47, 48], [1, 9, 41, 49], [1, 9, 41, 49], [2, 2, 47, 49], [1, 3, 47, 49], [1, 3, 47, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 48, 49], [1, 2, 47, 50], [1, 2, 47, 50], [1, 2, 47, 50], [1, 2, 47, 50], [1, 1, 48, 50]]


DFS去重打印:大小:20
[1, 1, 2, 47, 49] [1, 1, 3, 47, 48] [2, 9, 41, 48] [1, 49, 50] [1, 2, 2, 47, 48] [3, 9, 41, 47] [2, 48, 50] [3, 48, 49] [3, 47, 50] [1, 2, 47, 50] [1, 3, 47, 49] [1, 1, 9, 41, 48] [2, 2, 47, 49] [2, 3, 47, 48] [1, 1, 48, 50] [1, 2, 48, 49] [1, 2, 9, 41, 47] [9, 41, 50] [1, 1, 2, 2, 3, 41, 50] [1, 9, 41, 49] 


	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int[] questions = new int[n];
		for (int i = 0; i < questions.length; i++) {
			questions[i] = sc.nextInt();
		}

		System.out.println("是否可以:" + findSum(questions, 100));
		System.out.println("有几种:" + findSum2(questions, 100));
		System.out.println("动规不去重打印: " + "大小:" + findSums(questions, 100).size() + findSums(questions, 100));
		System.out.println("迭代不去重打印: " + "大小:" + findSums2(questions, 100).size() + " " + findSums2(questions, 100));
		System.out.println("m个和为n:" + CalSum(questions, 100, 4));

		HashSet<List<Integer>> result = new HashSet<>();
		dfs(0, 0, 100, questions, new ArrayList<Integer>(), result);
		System.out.println("DFS去重打印:" + "大小:" + result.size());
		for (List<Integer> i : result) {
			System.out.print(i + " ");
		}

	}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值