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