Skip to content

Commit e6aa58c

Browse files
author
Kai Yang
committed
40. Combination Sum II
1 parent 04b855e commit e6aa58c

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

40.CombinationSumII.Test.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Newtonsoft.Json;
5+
using NUnit.Framework;
6+
7+
[TestFixture]
8+
public class TestClass : TestClassBase
9+
{
10+
[TestCase("[1,2,3]", 3)]
11+
[TestCase("[10,7,4,10,8,4,2,3,9,9]", 55)]
12+
public void TestMethod1(string candidatesString, int target)
13+
{
14+
var candidates = JsonConvert.DeserializeObject<int[]>(candidatesString);
15+
var expectedResult = CombinationSum2(candidates, target);
16+
var result = new Solution().CombinationSum2(candidates, target);
17+
Assert.AreEqual(Serialize(expectedResult), Serialize(result), string.Format("{0}. {1}.", candidatesString, target));
18+
}
19+
20+
[TestCase(10, 10, 100)]
21+
public void TestMethod2(int maxLength, int maxValue, int repeatTimes)
22+
{
23+
Repeat(repeatTimes, () =>
24+
{
25+
var candidates = GenerateIntegerArray(0, maxLength, 1, maxValue);
26+
var candidatesString = JsonConvert.SerializeObject(candidates);
27+
var target = Random.Next(1, Math.Max(2, candidates.Sum() + 2));
28+
TestMethod1(candidatesString, target);
29+
});
30+
}
31+
32+
private IList<IList<int>> CombinationSum2(int[] candidates, int target)
33+
{
34+
var results = new List<IList<int>>();
35+
Search(results, new Stack<int>(), candidates, target, 0);
36+
results = results.GroupBy(item => JsonConvert.SerializeObject(item)).Select(g => g.First()).ToList();
37+
return results;
38+
}
39+
40+
private void Search(IList<IList<int>> results, Stack<int> temp, int[] candidates, int remaining, int index)
41+
{
42+
if (remaining == 0)
43+
{
44+
if (temp.Count > 0)
45+
{
46+
results.Add(temp.OrderBy(x => x).ToList());
47+
}
48+
return;
49+
}
50+
if (remaining < 0 || index >= candidates.Length)
51+
{
52+
return;
53+
}
54+
temp.Push(candidates[index]);
55+
Search(results, temp, candidates, remaining - candidates[index], index + 1);
56+
temp.Pop();
57+
Search(results, temp, candidates, remaining, index + 1);
58+
}
59+
60+
private string Serialize(IList<IList<int>> results)
61+
{
62+
return JsonConvert.SerializeObject(results.OrderBy(item => JsonConvert.SerializeObject(item)).Select(item => item));
63+
}
64+
}

40.CombinationSumII.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
public class Solution
6+
{
7+
public IList<IList<int>> CombinationSum2(int[] candidates, int target)
8+
{
9+
var dict = new SortedDictionary<int, int>(candidates.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count()));
10+
var paths = new List<Tuple<int, int>>[target + 1];
11+
paths[0] = new List<Tuple<int, int>>();
12+
foreach (var pair in dict)
13+
{
14+
for (var j = target; j >= 0; --j)
15+
{
16+
for (var k = 1; k <= pair.Value && j - pair.Key * k >= 0; ++k)
17+
{
18+
if (paths[j - pair.Key * k] != null)
19+
{
20+
if (paths[j] == null)
21+
{
22+
paths[j] = new List<Tuple<int, int>>();
23+
}
24+
paths[j].Add(Tuple.Create(pair.Key, k));
25+
}
26+
}
27+
}
28+
}
29+
30+
var results = new List<IList<int>>();
31+
if (paths[target] != null) GenerateResults(results, new Stack<int>(), paths, target, paths[target].Count - 1);
32+
return results;
33+
}
34+
35+
private void GenerateResults(IList<IList<int>> results, Stack<int> result, List<Tuple<int, int>>[] paths, int remaining,
36+
int maxIndex)
37+
{
38+
if (remaining == 0)
39+
{
40+
results.Add(new List<int>(result));
41+
return;
42+
}
43+
for (var i = maxIndex; i >= 0; --i)
44+
{
45+
var path = paths[remaining][i];
46+
for (var j = 0; j < path.Item2; ++j)
47+
{
48+
result.Push(path.Item1);
49+
}
50+
var nextMaxIndex = paths[remaining - path.Item1 * path.Item2].BinarySearch(Tuple.Create(path.Item1, int.MinValue), Comparer.Instance);
51+
nextMaxIndex = ~nextMaxIndex - 1;
52+
GenerateResults(results, result, paths, remaining - path.Item1 * path.Item2, nextMaxIndex);
53+
for (var j = 0; j < path.Item2; ++j)
54+
{
55+
result.Pop();
56+
}
57+
}
58+
}
59+
}
60+
61+
class Comparer : IComparer<Tuple<int, int>>
62+
{
63+
public int Compare(Tuple<int, int> x, Tuple<int, int> y)
64+
{
65+
if (x.Item1 < y.Item1) return -1;
66+
if (x.Item1 > y.Item1) return 1;
67+
return x.Item2.CompareTo(y.Item2);
68+
}
69+
70+
public static Comparer Instance = new Comparer();
71+
}

0 commit comments

Comments
 (0)