1+ function combinationSum ( candidates : number [ ] , target : number ) : number [ ] [ ] {
2+ /*
3+ * 합이 target이 되는 candidates 경우의 수를 리턴
4+ * cadidates는 고유함
5+ * 합이 target이 되지 않는 경우, 빈배열 리턴
6+ * cadidate을 중복 사용 가능
7+ * 2 <= candidates[i] <= 40
8+ * => candidate이 1인 경우는 없음
9+ * candidates에서 target보다 같거나 작은 값만 filter하고 시작 (target보다 큰 값은 후보군이 될 수 없음)
10+ *
11+
12+ * [2,3,6,7] / 7
13+ *
14+ * []
15+ * [2] / 5
16+ * [2, 2] 3 => X
17+ * [2, 2, 2] 1 => X
18+ * [2, 2, 2, 2] -1 => X
19+ * [2, 2, 2, 3] -2 => X
20+ * [2, 2, 2, 6] -5 => X
21+ * [2, 2, 2, 7] -6 => X
22+ [2, 2, 3] 0 => O
23+ // ...
24+ [2, 3] 2 => X
25+ [2, 3, 2] 0 => O
26+ // ...
27+ [2, 6] -1 => X
28+ // ...
29+
30+ *
31+ * 하나씩 값을 추가하면서 배열의 총합을 target 값과 비교한다
32+ * sum이 target값보다 작으면 계속 다음 값을 추가해준다
33+ * sum이 target과 같으면 결과 값 result 배열에 추가해준다.
34+ * sum이 target보다 넘으면 마지막에 추가한 값을 뺀다.
35+ * 이 과정을 반복하며 배열에서 결과 값을 찾는다.
36+ *
37+ */
38+
39+ // TC: O(2^N) N = candidates.length
40+ // SC: O(T) T = target
41+ function backtrack ( candidates : number [ ] , start :number , total :number ) {
42+ if ( target === total ) {
43+ result . push ( [ ...path ] )
44+ return
45+ }
46+
47+ if ( target < total ) {
48+ return
49+ }
50+
51+ for ( let i = start ; i <= candidates . length - 1 ; i ++ ) {
52+ path . push ( candidates [ i ] )
53+ backtrack ( candidates , i , total + candidates [ i ] )
54+ path . pop ( )
55+ }
56+ }
57+
58+ const result = [ ]
59+ const path = [ ]
60+ // TC: O(NlogN)
61+ // SC: O(N)
62+ const filteredCandidates = candidates . filter ( candidate => candidate <= target ) . sort ( ( a , b ) => a - b )
63+ backtrack ( filteredCandidates , 0 , 0 )
64+ return result
65+
66+ } ;
67+ // TC: O(2^N)
68+ // SC: O(2^N)
69+
70+ / * # S o l u t i o n 2 : D P
71+ * candidates을 가지고 target 값을 만들 수 있는 모든 조합을 미리 찾아둔다 .
72+ * candidates [ 2 , 3 , 6 , 7 ] / target 7 라고 했을때
73+ * 1 ) candidate = 2
74+ * dp [ 2 ] = [ [ 2 ] ]
75+ * dp [ 4 ] = [ [ 2 , 2 ] ]
76+ * dp [ 6 ] = [ [ 2 , 2 , 2 ] ]
77+ * 2 ) candidate = 3
78+ * dp [ 3 ] = [ [ 3 ] ]
79+ * dp [ 5 ] = [ [ 2 , 3 ] ]
80+ * dp [ 6 ] = [ [ 2 , 2 , 2 ] , [ 3 , 3 ] ]
81+ * dp [ 7 ] = [ [ 2 , 2 , 3 ] ]
82+ * 3 ) candidate = 6
83+ * dp [ 6 ] = [ [ [ 2 , 2 , 2 ] , [ 3 , 3 ] , [ 6 ] ]
84+ * 4 ) candidate = 7
85+ * dp [ 7 ] = [ [ 2 , 2 , 3 ] , [ 7 ] ]
86+ *
87+ * => dp = [
88+ * [ [ ] ]
89+ * [ [ ] ]
90+ * [ [ 2 ] ]
91+ * [ [ 3 ] ]
92+ * [ [ 2 , 2 ] ]
93+ * [ [ 2 , 3 , ] ]
94+ * [ [ 2 , 2 , 2 ] , [ 3 , 3 ] , [ 6 ] ]
95+ * [ [ 2 , 2 , 3 ] , [ 7 ] ]
96+ * ]
97+ * ]
98+ * /
99+
100+
101+
102+ // SC: O(T+1) T = target
103+ const dp = Array . from ( { length : target + 1 } , ( ) => [ ] ) ;
104+ dp [ 0 ] = [ [ ] ] ;
105+
106+
107+ // TC: O(C), C = candidates.length
108+ for ( let candidate of candidates ) {
109+ // TC: O(T) T = target
110+ for ( let i = candidate ; i <= target ; i ++ ) {
111+ // TC: O(K) K = dp[i - candidate].length
112+ // SC: O(K)
113+ for ( let combination of dp [ i - candidate ] ) {
114+ dp [ i ] . push ( [ ...combination , candidate ] ) ;
115+ }
116+ }
117+ }
118+
119+ return dp [ target ] ;
120+ }
121+
122+ // TC: O(C * T * K)
123+ // SC: O((T+1) * K* T)
0 commit comments