diff --git a/coin-change/dev-jonghoonpark.md b/coin-change/dev-jonghoonpark.md new file mode 100644 index 000000000..2f3afeb7a --- /dev/null +++ b/coin-change/dev-jonghoonpark.md @@ -0,0 +1,67 @@ +- 문제: https://leetcode.com/problems/coin-change/ +- 풀이: https://algorithm.jonghoonpark.com/2024/02/26/leetcode-322 + +## dfs로 풀기 + +```java +class Solution { + public int coinChange(int[] coins, int amount) { + if(amount == 0) { + return 0; + } + + int[] dp = new int[amount + 1]; + + List sortedCoins = Arrays.stream(coins).boxed() + .sorted(Collections.reverseOrder()) + .toList(); + + sortedCoins.forEach(coin -> dfs(dp, sortedCoins, amount, coin)); + + return dp[0] == 0 ? -1 : dp[0]; + } + + void dfs(int[] dp, List coins, int amount, int selectedCoin) { + int currentPointer = amount - selectedCoin; + if (currentPointer < 0) { + return; + } + + if (dp[currentPointer] == 0 || dp[currentPointer] > dp[amount] + 1) { + dp[currentPointer] = dp[amount] + 1; + coins.forEach(coin -> dfs(dp, coins, currentPointer, coin)); + } + } +} +``` + +### TS, SC + +코인의 수를 n 이라고 했을 때, `O(n * amount ^ 2)` 의 시간복잡도와 `O(amount)` 의 공간복잡도를 가진다. + +## dp로 풀기 + +```java +public class Solution { + public int coinChange(int[] coins, int amount) { + int max = amount + 1; + int[] dp = new int[amount + 1]; + Arrays.fill(dp, max); + dp[0] = 0; + + for (int i = 1; i <= amount; i++) { + for (int j = 0; j < coins.length; j++) { + if (coins[j] <= i) { + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); + } + } + } + + return dp[amount] > amount ? -1 : dp[amount]; + } +} +``` + +### TS, SC + +코인의 수를 n 이라고 했을 때, `O(n * amount)` 의 시간복잡도와 `O(amount)` 의 공간복잡도를 가진다. diff --git a/decode-ways/dev-jonghoonpark.md b/decode-ways/dev-jonghoonpark.md new file mode 100644 index 000000000..47d3644b2 --- /dev/null +++ b/decode-ways/dev-jonghoonpark.md @@ -0,0 +1,44 @@ +- 문제: https://leetcode.com/problems/decode-ways/ +- 풀이: https://algorithm.jonghoonpark.com/2024/07/08/leetcode-91 + +```java +class Solution { + public int numDecodings(String s) { + int[] dp = new int[s.length()]; + + if (s.charAt(0) == '0') { + return 0; + } + dp[0] = 1; + + for (int i = 1; i < s.length(); i++) { + int oneDigit = Integer.parseInt(String.valueOf(s.charAt(i))); + if (oneDigit > 0) { + dp[i] = dp[i - 1]; + } + + int prevDigit = Integer.parseInt(String.valueOf(s.charAt(i - 1))); + if (prevDigit == 0) { + continue; + } + + int twoDigit = prevDigit * 10 + oneDigit; + if (twoDigit <= 26) { + if (i > 2) { + dp[i] = dp[i] + dp[i - 2]; + } else { + dp[i] = dp[i] + 1; + } + } + } + + return dp[s.length() - 1]; + } +} +``` + +### TC, SC + +시간 복잡도는 O(n), 공간 복잡도는 O(n)이다. +이런식으로 최근 데이터만 재사용 하는 경우에는 공간복잡도를 O(1) 으로도 줄일 수 있을 것이다. +최근의 데이터가 아닌 이전 데이터들은 더 이상 참조되지 않기 때문에 필요한 공간만 만들어서 보관하면 된다. diff --git a/maximum-product-subarray/dev-jonghoonpark.md b/maximum-product-subarray/dev-jonghoonpark.md new file mode 100644 index 000000000..87ef4d6c3 --- /dev/null +++ b/maximum-product-subarray/dev-jonghoonpark.md @@ -0,0 +1,57 @@ +- 문제: https://leetcode.com/problems/maximum-product-subarray/ +- 풀이: https://algorithm.jonghoonpark.com/2024/07/09/leetcode-152 + +```java +class Solution { + public int maxProduct(int[] nums) { + int max = Integer.MIN_VALUE; + int temp = 0; + int lastZeroIndex = 0; + for (int i = 0; i < nums.length; i++) { + int current = nums[i]; + if (temp == 0) { + temp = current; + lastZeroIndex = i; + } else { + if (current == 0) { + temp = 0; + } else if (temp > 0 && current < 0) { + if (hasNextMinus(nums, i + 1)) { + temp = temp * current; + } else { + temp = temp * current; + for (int j = lastZeroIndex; j < i + 1; j++) { + temp = temp / nums[j]; + if (temp > 0) { + break; + } + } + } + } else { + temp = temp * current; + } + } + max = Math.max(max, temp); + if (temp < 0 && !hasNextMinus(nums, i + 1)) { + temp = 0; + } + } + return max; + } + + private boolean hasNextMinus(int[] nums, int i) { + for (; i < nums.length; i++) { + if (nums[i] < 0) { + return true; + } else if (nums[i] == 0) { + return false; + } + } + return false; + } +} +``` + +### TC, SC + +시간 복잡도는 O(n^2)이다. 공간 복잡도는 O(1)이다. hasNextMinus 이 적게 호출된다면 시간 복잡도는 O(n)에 가깝게 동작한다. diff --git a/palindromic-substrings/dev-jonghoonpark.md b/palindromic-substrings/dev-jonghoonpark.md new file mode 100644 index 000000000..ce04eab40 --- /dev/null +++ b/palindromic-substrings/dev-jonghoonpark.md @@ -0,0 +1,37 @@ +- 문제: https://leetcode.com/problems/palindromic-substrings/ +- 풀이: https://algorithm.jonghoonpark.com/2024/07/08/leetcode-647 + +```java +class Solution { + public int countSubstrings(String s) { + int count = 0; + + char[] charArray = s.toCharArray(); + for (int i = 0; i < s.length(); i++) { + char currentChar = charArray[i]; + count++; + + int left = i; + int right = i; + + while (right < s.length() - 1 && currentChar == charArray[right + 1]) { + right++; + count++; + } + + while (left > 0 && right < s.length() - 1 && charArray[left - 1] == charArray[right + 1]) { + left--; + right++; + count++; + } + } + + return count; + } +} +``` + +### TC, SC + +시간 복잡도는 평균적으로 O(n)이다. palindrome 의 길이가 n 에 가까워질수록 시간 복잡도는 O(n^2) 에 가까워 진다. +공간 복잡도는 O(n)이다. diff --git a/word-break/dev-jonghoonpark.md b/word-break/dev-jonghoonpark.md new file mode 100644 index 000000000..9c99157ad --- /dev/null +++ b/word-break/dev-jonghoonpark.md @@ -0,0 +1,28 @@ +- 문제: https://leetcode.com/problems/word-break/ +- 풀이: https://algorithm.jonghoonpark.com/2024/02/28/leetcode-139 + +```java +class Solution { + public boolean wordBreak(String s, List wordDict) { + boolean[] dp = new boolean[s.length() + 1]; + dp[0] = true; + + for (int i = 1; i <= s.length(); i++) { + for (String word : wordDict) { + if (i >= word.length()) { + int start = i - word.length(); + if (dp[start] && s.startsWith(word, start)) { + dp[i] = true; + } + } + } + } + + return dp[s.length()]; + } +} +``` + +### TC, SC + +s의 길이를 n 이라 하고, wordDict의 크기를 m 이라고 할 때, 시간복잡도는 `O(n * m)` 공간복잡도는 `O(n)` 이다.