Skip to content

Commit f9f6ffd

Browse files
committed
feat: combination-sum 중복 로직을 제거해서 복잡도 개선
1 parent 84a19e1 commit f9f6ffd

File tree

1 file changed

+65
-5
lines changed

1 file changed

+65
-5
lines changed

combination-sum/haxr369.java

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import java.util.ArrayList;
2+
import java.util.Arrays;
23
import java.util.HashSet;
34
import java.util.List;
45
import java.util.Set;
@@ -11,6 +12,65 @@
1112
*/
1213
class Solution {
1314

15+
/**
16+
* 중복순열을 구하는 부분은 2번 풀이와 동일하지만,
17+
* 후보배열을 정렬하고, 후보 선택 시 이전 값과 같거나 큰 후보만을 선택하기에
18+
* 동일 요소가 존재하는 배열을 중복해서 만들지 않음.
19+
* 또한 Set 같은 저장위치를 제거해서 메모리 최적화.
20+
*
21+
* Runtime: 5 ms (Beats 8.49%)
22+
* Memory: 45.77 MB (Beats 16.78%)
23+
* Space Complexity: O(N)
24+
* - 사용된 후보를 저장하는 배열 O(N)
25+
* > O(N)
26+
* Time Complexity: O(2^N/N!)
27+
* - 후보 하나를 선택해서 target과 비교 => O(2^N)
28+
* - target이 0이 되거나 누적 값이 더 커질 때까지 스택을 쌓기
29+
* - 최대 누적할 수 있는 횟수는 40 / 2 = 20회 => O(20) = O(M)
30+
* - 다만, 중복배열 생성을 방지하는 트릭을 추가함 O(1/N!)
31+
* > O(2^N/N!)
32+
*
33+
* @param candidates
34+
* @param target
35+
* @return
36+
*/
37+
public List<List<Integer>> combinationSum(int[] candidates, int target) {
38+
List<List<Integer>> ans = new ArrayList<>();
39+
List<Integer> acc = new ArrayList<>();
40+
Arrays.sort(candidates);
41+
42+
makecombination(ans, acc, target, candidates, 0);
43+
return ans;
44+
}
45+
46+
/**
47+
* 이전에 더했던 후보와 같거나 큰 후보만 더한다.
48+
* set: return용 조합 저장
49+
* acc: 사용 후보 누적
50+
* usedCount: 후보별 사용된 횟수 저장
51+
* target: 만들 수
52+
*/
53+
private void makecombination(List<List<Integer>> set, List<Integer> acc, int target, int[] candidates,
54+
int idx) {
55+
// 완성된 경우 리턴하기
56+
if (target == 0) {
57+
List<Integer> tmp = new ArrayList<>(acc); // 깊은 복사
58+
set.add(tmp);
59+
return;
60+
} else if (target < 0 || idx >= candidates.length) { // 타겟이 0 보다 작은 경우 스킵
61+
return;
62+
}
63+
64+
// 현재 인덱스 후보 사용
65+
acc.add(candidates[idx]);
66+
makecombination(set, acc, target - candidates[idx], candidates, idx);
67+
acc.remove(acc.size() - 1); // 마지막 요소 제거
68+
69+
// 다음 인덱스 후보 사용
70+
makecombination(set, acc, target, candidates, idx + 1);
71+
return;
72+
}
73+
1474
/**
1575
* candidates의 후보들은 중복 사용이 가능하다.
1676
* 모든 후보는 구별된다.=> 중복이 없다.
@@ -21,11 +81,10 @@ class Solution {
2181
* - 사용되는 후보를 Set으로 관리하기 => O(N)
2282
* - 후보가 사용된 횟수를 관리하기 => O(K)
2383
* > O(N) + O(K)
24-
* Time Complexity: O(N)
25-
* - 후보 하나를 선택해서 target과 비교 => O(N^M)
26-
* - target이 0이 되거나 누적 값이 더 커질 때까지 스택을 쌓기
27-
* - 최대 누적할 수 있는 횟수는 40 / 2 = 20회 => O(20) = O(M)
28-
* > O(N)*O(M)
84+
* Time Complexity: O(2^N)
85+
* - 후보 하나를 선택해서 target과 비교
86+
* - target이 0이 되거나 누적 값이 더 커질 때까지 스택을 쌓기 => O(2^N)
87+
* > O(2^N)
2988
*/
3089
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
3190
Set<List<Integer>> set = new HashSet<>();
@@ -38,6 +97,7 @@ public List<List<Integer>> combinationSum2(int[] candidates, int target) {
3897
}
3998

4099
/**
100+
* target을 만드는 순열을 만든다.. => 중복을 포함하기 때문에 중복 연산이 많다..
41101
* set: return용 조합 저장
42102
* acc: 사용 후보 누적
43103
* usedCount: 후보별 사용된 횟수 저장

0 commit comments

Comments
 (0)