问题:从 1 到 9 中选择 k 个不重复的数字,使它们相加起来等于 n。
例1: 输入 k = 3, n = 7; 输出 [[1,2,4]]
例2: 输入 k = 3, n = 9; 输出 [[1,2,6], [1,3,5], [2,3,4]]
C#代码:
using System; using System.Collections.Generic; public class Solution { /// <summary> /// 从1到9中,选择k个不同的数字,使其和等于n /// </summary> /// <param name="k">选择的数字个数</param> /// <param name="n">数字的和</param> /// <returns>复合条件的数字集合</returns> public IList<IList<int>> CombinationSum3(int k, int n) { int[] allNums = new int[10]; int[] tagNums = new int[10]; List<string> results = new List<string>(); Solution p = new Solution(); for (int i = 1; i < 10; i++) { allNums[i - 1] = i; } //这里备选数字集合为1-9这9个数 p.Combine(allNums, 9, k, tagNums, k, results); IList<IList<int>> correctList = new List<IList<int>>(); foreach (var res in results) { int sum = 0; List<int> correct = new List<int>(); //计算各串数字的和 for (int j = 0; j < res.Length; j++) { sum += Convert.ToInt16(res[j].ToString()); } if (sum == n) { for (int m = 0; m <= res.Length - 1; m++) { correct.Add(Convert.ToInt16(res[m].ToString())); } correctList.Add(correct); } //清空sum的值 sum = 0; } return correctList; } /// <summary> /// 输出给定数字范围内的所有组合(非排列)结果 /// </summary> /// <param name="allNums">备选数字集合</param> /// <param name="needCount">在备选数字集合中,选择 needCount 个中数字来进行再次选择</param> /// <param name="childCount">取 childCount 个数字进行组合</param> /// <param name="tagNums">存放每次选中的 childCount 个数字在备选数字集合中的位置</param> /// <param name="backupChildCount">存放 childCount 的值</param> /// <param name="results">所有组合(非排列)结果</param> public void Combine(int[] allNums, int needCount, int childCount, int[] tagNums, int backupChildCount, List<string> results) { for (int i = needCount; i >= childCount; i--) { //选择第一个数字,记录它在 allNums 数组中的位置 tagNums[childCount - 1] = i - 1; //如果选中的数字个数未达到 childCount 个,则继续选择下一个 if (childCount > 1) { Combine(allNums, i - 1, childCount - 1, tagNums, backupChildCount, results); } else { string res = ""; for (int j = 0; j <= backupChildCount - 1; j++) { res += allNums[tagNums[j]].ToString(); } results.Add(res); } } } }
参考资料:http://bbs.csdn.net/topics/390242147
输出组合数(回溯法)
public class Solution { public const int MAXN = 100; public int[] a = new int[MAXN]; static void Main(string[] args) { Solution p = new Solution(); p.comb(9, 3); System.Console.ReadKey(); } void comb(int m, int r) /* 求从自然数1到m中任取3个数的所有组合子程序 */ { int i, j; i = 0; a[i] = 1; /* 初始规模为1时,a[0]为1 */ do { if (a[i] - i <= m - r + 1) /* 还可以向前试探 */ { if (i == r - 1) /* 当前候选解的视图满足问题的规模要求,找到一个解 */ { for (j = 0; j < r; j++) System.Console.Write(a[j] + " "); System.Console.Write(" "); a[i]++; /* 考查当前规模的下一个候选解 */ continue; } i++; a[i] = a[i - 1] + 1; } else { /* 当前规模的候选解已经全部考查完毕,则应回溯,缩小规模 */ if (i == 0) /* 回溯至初始规模,则已经全部找到了解 */ return; a[--i]++; /* 缩小规模,考查下一个候选解 */ } } while (true); } }
参考资料:软件设计师考试辅导教程