-
-
Notifications
You must be signed in to change notification settings - Fork 362
[namuuCY] WEEK 03 Solutions #2709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // 문제풀이 흐름 | ||
| // 하나를 집어넣고, 모자라면 이전과 동일한걸 집어넣거나 더 큰걸 집어넣는 방식으로 계속 확인 | ||
| // -> 백트래킹 방식 | ||
|
|
||
| // n = candidates.length / m = candidates[0] 라 할때, | ||
| // 시간복잡도 : | ||
| // 이론상 O(n ^ (target / m)) | ||
| // 150 조합 이내로 뽑히게끔 만들어뒀으므로 알아서 잘되지 않았을까... | ||
| // 공간복잡도 : | ||
| // O(target / m) - 재귀 깊이만큼 | ||
|
|
||
|
|
||
| class Solution { | ||
|
|
||
| List<List<Integer>> answer = new ArrayList<>(); | ||
| int[] candidates; | ||
| int target; | ||
|
|
||
| public List<List<Integer>> combinationSum(int[] candidates, int target) { | ||
| this.candidates = candidates; | ||
| this.target = target; | ||
|
|
||
| backtracking(new ArrayList<>(), 0, target); | ||
| return answer; | ||
| } | ||
|
|
||
| public void backtracking(List<Integer> combination, int currentIdx, int remainder) { | ||
| if (remainder == 0) { | ||
| answer.add(new ArrayList<>(combination)); | ||
| return; | ||
| } else if (remainder < 0) { | ||
| return; | ||
| } | ||
|
|
||
| for (int i = currentIdx ; i < candidates.length ; i++) { | ||
| combination.add(candidates[i]); | ||
| backtracking(combination, i, remainder - candidates[i]); | ||
| combination.remove(combination.size() - 1); | ||
| } | ||
| } | ||
| } |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 각 위치에서 가능한 단일 숫자 해석과 두 자리 조합 해석 여부를 확인하여 부분해를 합산합니다. 개선 제안: 현재 구현이 적절해 보입니다.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1개 파싱이랑 2개 파싱하는 부분 함수로 따로 빼서 코드 깔끔하게 하신거 인상적이네요!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 문제도 공간복잡도 O(1)에 해결 가능하니 나중에 시도 해보시면 좋겠네요 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // 문제 풀이 흐름 | ||
| // DP[i] = i - 1 번째 인덱스 char를 끝으로 하는 조합 | ||
| // 문제는 case를 다 분리할 수 밖에 없는건가? | ||
| // 7~9 이면 앞자리가 1인지 확인 -> 있으면 두가지 합해야함 / 아니면 한가지만 | ||
| // 0이면 앞자리가 반드시 1,2 이어야함 -> 무조건 한가지 | ||
| // 1~6이면 앞자리가 1,2인지 확인 -> 있으면 두가지 합해야함 / 아니면 한가지만 | ||
| // 이러면 너무 더러운 느낌? | ||
| // if () { | ||
| // if () | ||
| // } else if () { | ||
| // if () | ||
| // } else { | ||
| // } | ||
|
|
||
| // 추가적으로 고려하지 못한 사항 : 01, 001 과 같은 경우 | ||
|
|
||
| // n = s의 길이 | ||
| // 시간복잡도 : O(n) | ||
| // 공간복잡도 : O(n) | ||
|
|
||
|
|
||
| class Solution { | ||
|
|
||
| String s; | ||
| int length; | ||
| int[] DP; | ||
|
|
||
| public int numDecodings(String s) { | ||
|
|
||
| this.s = s; | ||
| this.length = s.length(); | ||
| this.DP = new int[this.length + 1]; | ||
|
|
||
| DP[0] = 1; | ||
|
|
||
| for (int i = 1 ; i < this.length + 1; i ++) { | ||
|
|
||
| if (canDecodeSingle(i)) { | ||
| DP[i] += DP[i - 1]; | ||
| } | ||
|
|
||
| if (i >= 2 && canDecodePair(i)) { | ||
| DP[i] += DP[i - 2]; | ||
| } | ||
| } | ||
|
|
||
| return DP[this.length]; | ||
| } | ||
|
|
||
| private boolean canDecodeSingle(int currentIdx) { | ||
| return s.charAt(currentIdx - 1) != '0'; | ||
| } | ||
|
|
||
| private boolean canDecodePair(int currentIdx) { | ||
| char currentChar = s.charAt(currentIdx - 1); | ||
| char prevChar = s.charAt(currentIdx - 2); | ||
| return prevChar == '1' | ||
| || (prevChar == '2' && currentChar <= '6'); | ||
| } | ||
| } |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: DP 배열을 사용해 각 위치까지의 최댓값을 누적 계산합니다. 개선 제안: 현재 구현이 적절해 보입니다.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 문제 깔끔하게 해결하시긴 했는데
로 해결하는 방법도 있어서 어차피 시간 많이 남았으니 천천히 한번 찾아 보시는 것도 좋을 것 같습니다! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // 문제 풀이 흐름 | ||
| // 맨처음에 생각한 풀이는 | ||
| // 누적합을 기준으로, | ||
| // 누적합의 오른쪽 최대 - 왼쪽 최소 의 값이 제일 큰걸 구하면 된다고 생각했음. | ||
| // 예를 들어서 nums = [-2,1,-3,4,-1,2,1,-5,4] 라면 | ||
| // 누적합은 [-2 -1 -4 0 -1 1 2 -3] 이 되는데, 값의 최대는 2에서 -4를 뺸 6이 최대라고 생각했음. | ||
| // 그래서 어느 한 좌표(왼쪽)를 순회하면서 | ||
| // 이 인덱스의 오른쪽(왼쪽 인덱스 +1 부터 끝까지)의 누적합의 최소를 구하면 된다고 생각했음. | ||
| // 이 위를 구하기 위해서 누적합에 대해 세그먼트 트리를 구축해두려고 했음. | ||
| // 그러면 세그먼트 트리 만드는데 nlogn + 1중 for 문 * log n 조회니까 최대 nlogn의 시간복잡도로 문제를 풀수있음 / 공간복잡도는 O(n log n)이 될것. | ||
|
|
||
| // 근데 제시된 풀이를 보니까 1차원 DP로 푸는것을 봤음. | ||
| // DP[i] = Math.max(nums[i], DP[i - 1] + nums[i]); | ||
| // 혹은 = nums[i] + (DP[i - 1] > 0) ? DP[i - 1] : 0; 이 되겠지. | ||
| // 이렇게 하면 시간복잡도 O(n) 공간복잡도 O(n)이라 내 풀이보다 훨씬좋다 | ||
|
|
||
| class Solution { | ||
|
|
||
| public int maxSubArray(int[] nums) { | ||
| int[] DP = new int[nums.length + 1]; | ||
| int maxSum = - 200000; | ||
|
|
||
| for (int i = 0 ; i < nums.length; i ++) { | ||
| DP[i + 1] = nums[i] + (DP[i] > 0 ? DP[i] : 0); | ||
| maxSum = Math.max(maxSum, DP[i + 1]); | ||
| } | ||
|
|
||
| return maxSum; | ||
| } | ||
| } |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 입력 정수 n의 비트를 하나씩 확인하며 1의 개수를 증가시킵니다. 개선 제안: 현재 구현이 적절해 보입니다.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. % 연산보다 & 비트연산자가 보통 조금 빠르죠, 이걸 이용해서 해결하시면 정말 쥐똥만큼 최적화가 되긴 하겠지만 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // 문제풀이 흐름 | ||
| // 어떤 숫자를 2진수로 나타냈을때, 1의 개수를 구하는 것이므로 | ||
| // 2진수 변환과정에서 나오는 모든 1의 갯수만 세면 된다. | ||
|
|
||
| // 숫자 n에 대하여 | ||
| // 시간복잡도 : O(logn) | ||
| // 공간복잡도 : O(1) | ||
|
|
||
| class Solution { | ||
| public int hammingWeight(int n) { | ||
| int answer = 0; | ||
|
|
||
| while (n > 0) { | ||
| if (n % 2 == 1) answer ++; | ||
| n /= 2; | ||
| } | ||
|
|
||
| return answer; | ||
| } | ||
| } |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 두 포인터를 사용해 비알파 numeric 문자를 건너뛰고 비교합니다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // 문제 풀이 흐름 1 | ||
| // 먼저, 알파벳이 아닌 글자는 다 쳐내는 작업이 필요 | ||
| // 그 다음 알파벳으로만 만들어진 문자열에 대해 팰린드롬 확인 | ||
| // 길이 확인 후 | ||
| // 맨처음에서부터 중간까지, 대칭 값이 맞는지 확인 | ||
|
|
||
| // n = s의 길이라 할때 | ||
| // 시간복잡도 : O(n) | ||
| // 공간복잡도 : O(n) - 어쩔수없이 trimming한 문자열은 저장해야하므로 | ||
|
|
||
| // 문제 풀이 흐름 2 | ||
|
|
||
| // 문자열 그대로 팰린드롬 확인 스타트 | ||
| // 맨 앞과 뒤의 인덱스에서 시작해서 | ||
| // 알파벳이 아닌 다른 문자라면 skip | ||
| // 알파벳이라면 비교 | ||
|
|
||
| // n = s의 길이라 할때 | ||
| // 시간복잡도 : O(n) | ||
| // 공간복잡도 : O(1) | ||
|
|
||
|
|
||
| class Solution { | ||
| public boolean isPalindrome(String s) { | ||
| int rightIdx = s.length() - 1; | ||
|
|
||
| for (int leftIdx = 0 ; leftIdx <= rightIdx ; leftIdx ++) { | ||
| if (!isValid(s.charAt(leftIdx))) continue; | ||
|
|
||
| // rightIdx 조절 | ||
| while (leftIdx <= rightIdx && !isValid(s.charAt(rightIdx))) { | ||
| rightIdx--; | ||
| } | ||
|
|
||
| if (!isSameChar(s.charAt(leftIdx), s.charAt(rightIdx))) { | ||
| return false; | ||
| } | ||
| rightIdx-- ; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| private boolean isValid(char c) { | ||
| return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9'; | ||
| } | ||
|
Comment on lines
+44
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @namuuCY 안녕하세요 이번 주 리뷰를 맡게 된 최성호 입니다. 전체적으로 함수화를 잘 해주셨네요! Character.isLetterOrDigit()도 직접 구현해주셔서 |
||
|
|
||
| private boolean isSameChar(char a, char b) { | ||
| return Character.toLowerCase(a) == Character.toLowerCase(b); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 가지치기 없이 루프를 계속 진행하므로 최악의 경우 모든 재귀 트리 노드를 탐색합니다. 현재 구현은 재귀 깊이가 길어질 수 있습니다.
개선 제안: 고려해볼 만한 대안: 정렬 후 각 재귀 단계에서 남은 합계보다 큰 숫자는 더 이상 탐색하지 않도록 가지치기를 추가하면 성능을 크게 개선할 수 있습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 문제는 생각보다 DP로 구현했을때 이점이 많고, 또 아이디어가 그렇게 어렵지 않아서 한번 시도해보시는것도 좋을것 같네요!
백트래킹은 전반적으로 엄청 잘 구현하신것 같아요