From 27f04bca911b80e886d84454bddfefd2dc67c76a Mon Sep 17 00:00:00 2001 From: "changmuk.im" Date: Sat, 24 Aug 2024 23:27:04 +0900 Subject: [PATCH 1/3] solve : week 2 with python --- .../EGON.py | 84 +++++++++++++ counting-bits/EGON.py | 39 ++++++ decode-ways/EGON.py | 65 ++++++++++ encode-and-decode-strings/EGON.py | 116 ++++++++++++++++++ valid-anagram/EGON.py | 53 ++++++++ 5 files changed, 357 insertions(+) create mode 100644 construct-binary-tree-from-preorder-and-inorder-traversal/EGON.py create mode 100644 counting-bits/EGON.py create mode 100644 decode-ways/EGON.py create mode 100644 encode-and-decode-strings/EGON.py create mode 100644 valid-anagram/EGON.py diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/EGON.py b/construct-binary-tree-from-preorder-and-inorder-traversal/EGON.py new file mode 100644 index 000000000..4902dc904 --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/EGON.py @@ -0,0 +1,84 @@ +from typing import List, Optional +from unittest import TestCase, main + + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + +class Solution: + def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + return self.solve_1(preorder, inorder) + + """ + Runtime: 112 ms (Beats 66.16%) + Time Complexity: O(n ** 2) + Space Complexity: O(n) + Memory: 52.83 MB (Beats 63.14%) + """ + def solve_1(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + index = 0 + + def build_tree(preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + nonlocal index + + if not inorder: + return None + + if not 0 <= index < len(preorder): + return None + + root = TreeNode(preorder[index]) + index += 1 + split_index = inorder.index(root.val) + root.left = build_tree(preorder, inorder[:split_index]) + root.right = build_tree(preorder, inorder[split_index + 1:]) + + return root + + return build_tree(preorder, inorder) + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + preorder = [3, 9, 20, 15, 7] + inorder = [9, 3, 15, 20, 7] + output = TreeNode( + val=3, + left=TreeNode( + val=9 + ), + right=TreeNode( + val=20, + left=TreeNode(val=15), + right=TreeNode(val=7) + ) + ) + self.assertEqual(Solution.buildTree(Solution(), preorder, inorder), output) + + def test_2(self): + preorder = [-1] + inorder = [-1] + output = TreeNode( + val=-1 + ) + self.assertEqual(Solution.buildTree(Solution(), preorder, inorder), output) + + def test_3(self): + preorder = [1, 2] + inorder = [1, 2] + output = TreeNode( + val=1, + right=TreeNode( + val=2 + ) + ) + self.assertEqual(Solution.buildTree(Solution(), preorder, inorder), output) + + +if __name__ == '__main__': + main() diff --git a/counting-bits/EGON.py b/counting-bits/EGON.py new file mode 100644 index 000000000..abff4932e --- /dev/null +++ b/counting-bits/EGON.py @@ -0,0 +1,39 @@ +from typing import List +from unittest import TestCase, main + + +class Solution: + def countBits(self, n: int) -> List[int]: + return self.solve_1(n) + + """ + Runtime: 78 ms (Beats 31.22%) + Time Complexity: O(n * log n), 크기가 n인 배열의 원소들에 대해 시행마다 크기가 2로 나누어지는 비트연산을 수행하므로 + Space Complexity: O(1), 변수 저장 없이 바로 결과 반환 + Memory: 23.26 MB (Beats 39.52%) + """ + def solve_1(self, n: int) -> List[int]: + def count_number_of_1(n: int): + count = 0 + while n: + n &= (n - 1) + count += 1 + return count + + return [count_number_of_1(num) for num in range(n + 1)] + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + n = 2 + output = [0, 1, 1] + self.assertEqual(Solution.countBits(Solution(), n), output) + + def test_2(self): + n = 5 + output = [0, 1, 1, 2, 1, 2] + self.assertEqual(Solution.countBits(Solution(), n), output) + + +if __name__ == '__main__': + main() diff --git a/decode-ways/EGON.py b/decode-ways/EGON.py new file mode 100644 index 000000000..44beb1d99 --- /dev/null +++ b/decode-ways/EGON.py @@ -0,0 +1,65 @@ +from typing import List +from unittest import TestCase, main + + +class Solution: + def numDecodings(self, s: str) -> int: + return self.solve_1(s) + + """ + Runtime: 32 ms (Beats 80.36%) + Time Complexity: O(n) + Space Complexity: O(n) + Memory: 16.59 MB (Beats 51.72%) + """ + def solve_1(self, s: str) -> int: + if len(s) == 0: + return 0 + + if len(s) == 1: + return 0 if int(s) == 0 else 1 + + if len(s) == 2: + last_one_digit, last_two_digits = int(s[1]), int(s) + if last_one_digit == 0: + return 1 if 10 <= last_two_digits <= 26 else 0 + else: + if 0 <= last_two_digits < 10: + return 0 + elif 10 <= last_two_digits <= 26: + return 2 + else: + return 1 + + dp = [0] * (len(s) + 1) + dp[0], dp[1], dp[2] = self.solve_1(s[:0]), self.solve_1(s[:1]), self.solve_1(s[:2]) + for i in range(3, len(s) + 1): + last_one_digit, last_two_digits = int(s[i - 1]), int(s[i - 2: i]) + last_two_digits = int(s[i - 2: i]) + if last_one_digit == 0: + dp[i] += dp[i - 2] if 10 <= last_two_digits <= 26 else 0 + else: + dp[i] += dp[i - 1] + (dp[i - 2] if 10 <= last_two_digits <= 26 else 0) + + return dp[-1] + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + s = "226" + output = 3 + self.assertEqual(Solution.numDecodings(Solution(), s), output) + + def test_2(self): + s = "2101" + output = 1 + self.assertEqual(Solution.numDecodings(Solution(), s), output) + + def test_3(self): + s = "06" + output = 0 + self.assertEqual(Solution.numDecodings(Solution(), s), output) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/encode-and-decode-strings/EGON.py b/encode-and-decode-strings/EGON.py new file mode 100644 index 000000000..93db3589f --- /dev/null +++ b/encode-and-decode-strings/EGON.py @@ -0,0 +1,116 @@ +from functools import reduce +from typing import List +from unittest import TestCase, main + + +class Solution: + def encode(self, strs): + return self.encode_with_base64(strs) + + def decode(self, str): + return self.decode_with_base64(str) + + CSV_DELIMITER = ',' + + # solve_1. ASCII + """ + Runtime: - + Time Complexity: O(n * m), n은 strs 배열의 길이, m은 strs 배열의 각 문자열들의 평균 길이 + Space Complexity: O(n * m), n은 strs 배열의 길이, m은 encode/decode된 문자열의 평균 길이 + Memory: - + """ + def encode_with_ascii(self, strs: List[str]) -> str: + result = [] + for str in strs: + encoded_str = reduce( + lambda acc, cur: acc + cur, + map(lambda char: f'{ord(char)}'.zfill(3), str) + ) + result.append(encoded_str) + + return Solution.CSV_DELIMITER.join(result) + + def decode_with_ascii(self, str: str) -> List[str]: + encoded_strs = str.split(Solution.CSV_DELIMITER) + result = [] + for encoded_str in encoded_strs: + decoded_str = '' + for i in range(0, len(encoded_str), 3): + chunk = encoded_str[i: i + 3] + decoded_str += chr(int(chunk)) + result.append(decoded_str) + + return result + + # solve_2. Base64 + """ + Runtime: - + Time Complexity: O(n * m), n은 strs 배열의 길이, m은 strs 배열의 각 문자열들의 평균 길이 + Space Complexity: O(n * m), n은 strs 배열의 길이, m은 encode/decode된 문자열의 평균 길이 + Memory: - + """ + BASE64_CHAR_TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + + def encode_with_base64(self, strs: List[str]) -> str: + result = [] + + for str in strs: + bin_converted_str = reduce( + lambda acc, cur: acc + cur, + map(lambda char: bin(ord(char))[2:].zfill(8), str) + ) + + encoded_str = '' + for i in range(0, len(bin_converted_str), 6): + chunk = bin_converted_str[i: i + 6].ljust(6, '0') + base64_char = Solution.BASE64_CHAR_TABLE[int(chunk, 2)] + encoded_str += base64_char + encoded_str.ljust(4 - (len(encoded_str) % 4), '=') + + result.append(encoded_str) + + return Solution.CSV_DELIMITER.join(result) + + def decode_with_base64(self, str: str) -> List[str]: + result = [] + + encoded_strs = str.split(Solution.CSV_DELIMITER) + for encoded_str in encoded_strs: + encoded_str = encoded_str.rstrip('=') + bin_converted_str = reduce( + lambda acc, cur: acc + cur, + map(lambda char: bin(Solution.BASE64_CHAR_TABLE.index(char))[2:].zfill(6), encoded_str) + ) + + decoded_str = '' + for i in range(0, len(bin_converted_str), 8): + chunk = bin_converted_str[i: i + 8].rjust(8, '0') + decimal_value = int(chunk, 2) + if decimal_value != 0: + decoded_str += chr(decimal_value) + + result.append(decoded_str) + + return result + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + input = ["lint", "code", "love", "you"] + output = ["lint", "code", "love", "you"] + solution = Solution() + encoded = Solution.encode(solution, input) + decoded = Solution.decode(solution, encoded) + self.assertEqual(decoded, output) + + def test_2(self): + input = ["we", "say", ":", "yes"] + output = ["we", "say", ":", "yes"] + solution = Solution() + encoded = Solution.encode(solution, input) + decoded = Solution.decode(solution, encoded) + self.assertEqual(decoded, output) + + +if __name__ == '__main__': + main() diff --git a/valid-anagram/EGON.py b/valid-anagram/EGON.py new file mode 100644 index 000000000..f48e2feb8 --- /dev/null +++ b/valid-anagram/EGON.py @@ -0,0 +1,53 @@ +from unittest import TestCase, main +from collections import Counter + + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return self.solve_1(s, t) + + """ + Runtime: 46 ms (Beats 71.98%) + Time Complexity: O(n) + - 길이가 n인 str s, str t, dict counter를 순회하므로 O(3n) ~= O(n) + Space Complexity: O(n) + - 크기가 최대 n인 dict를 변수로 저장하여 사용하므로 O(n) + Memory: 16.88 MB (Beats 88.63%) + """ + def solve_1(self, s: str, t: str) -> bool: + counter = {} + for char in s: + counter[char] = counter.get(char, 0) + 1 + for char in t: + counter[char] = counter.get(char, 0) - 1 + + return any(counter.values()) is False + + """ + Runtime: 47 ms (Beats 67.45%) + Time Complexity: O(n) + - 크기가 n인 Counter 2개를 생성하므로 O(2n) ~= O(n) + Space Complexity: O(n) + - 크기가 n인 Counter 2개를 생성하므로 O(2n) ~= O(n) + Memory: 16.94 MB (Beats 46.26%) + """ + def solve_2(self, s: str, t: str) -> bool: + return Counter(s) is Counter(t) + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + s = "anagram" + t = "nagaram" + output = True + self.assertEqual(Solution.isAnagram(Solution(), s, t), output) + + def test_2(self): + s = "rat" + t = "car" + output = True + self.assertEqual(Solution.isAnagram(Solution(), s, t), output) + + +if __name__ == '__main__': + main() From d35be7d4179a0a409a189575bcf8d175d15db643 Mon Sep 17 00:00:00 2001 From: "changmuk.im" Date: Sat, 24 Aug 2024 23:27:14 +0900 Subject: [PATCH 2/3] solve : week 2 with swift --- counting-bits/EGON.swift | 113 +++++++++++++++++++++++++++ encode-and-decode-strings/EGON.swift | 68 ++++++++++++++++ valid-anagram/EGON.swift | 34 ++++++++ 3 files changed, 215 insertions(+) create mode 100644 counting-bits/EGON.swift create mode 100644 encode-and-decode-strings/EGON.swift create mode 100644 valid-anagram/EGON.swift diff --git a/counting-bits/EGON.swift b/counting-bits/EGON.swift new file mode 100644 index 000000000..39fe2f498 --- /dev/null +++ b/counting-bits/EGON.swift @@ -0,0 +1,113 @@ +import Foundation + +class Solution { + func countBits(_ n: Int) -> [Int] { + return solve_2(n) + } + + /* + **내장함수를 사용한 풀이** + + Runtime: 37 ms (Beats 49.12%) + Time Complexity: O(n * log n) + - 길이가 n인 range를 순회하므로 O(n) + - 정수에 대해 non zero bit를 세는데 O(log n) + > O(n * log n) + Space Complexity: O(n) + - 배열에 값을 저장하며 크기가 n이 되므로 O(n) + Memory: 20.86 MB (Beats 90.106%) + */ + func solve_1(_ n: Int) -> [Int] { + var result: [Int] = [] + for num in 0...n { + result.append(num.nonzeroBitCount) + } + return result + } + + /* + ** Brian Kernighan's Algorithm을 사용한 풀이 ** + + Runtime: 39 ms (Beats 42.11%) + Time Complexity: O(n * log n) + - 길이가 n인 range를 순회하므로 O(n) + - bitCountWithBrianKernighan 에서 내부 while문 실행마다 num이 절반으로 줄어드므로, 실행횟수는 O(log n) + > O(n * log n) + Space Complexity: O(n) + - 배열에 값을 저장하며 크기가 n이 되므로 O(n) + Memory: 16.01 MB (Beats 67.84%) + */ + func solve_2(_ n: Int) -> [Int] { + + func bitCountWithBrianKernighan(_ num: Int) -> Int { + var num = num + var bitCount = 0 + while 0 < num { + num &= (num - 1) + bitCount += 1 + } + + return bitCount + } + + var result: [Int] = [] + for num in 0...n { + result.append(bitCountWithBrianKernighan(num)) + } + return result + } + + /* + ** MSB에 대해 DP를 사용한 풀이 ** + > num의 비트 카운트 = MSB의 비트 카운트(1 고정) + (num - msb)의 비트 카운트 + + Runtime: 36 ms (Beats 58.48%) + Time Complexity: O(n) + - 0부터 n까지 range를 순회하므로 O(n) + > O(n) + Space Complexity: O(n) + - 길이가 n인 dp 배열을 저장하므로 O(n) + Memory: 21.15 MB (Beats 67.84%) + */ + func solve_3(_ n: Int) -> [Int] { + guard 1 <= n else { return [0] } + + var dp = [Int](repeating: 0, count: n + 1) + var msb = 1 + for num in 1...n { + if msb << 1 == num { + msb = num + } + + dp[num] = 1 + dp[num - msb] + } + + return dp + } + + /* + ** LSB에 대해 DP를 사용한 풀이 ** + > num의 비트 카운트 = num을 right shift한 숫자의 비트 카운트 + LSB의 비트 카운트(1 또는 0) + + Runtime: 28 ms (Beats 97.08%) + Time Complexity: O(n) + - 0부터 n까지 range를 순회하므로 O(n) + > O(n) + Space Complexity: O(n) + - 길이가 n인 dp 배열을 저장하므로 O(n) + Memory: 21.26 MB (Beats 53.80%) + */ + func solve_4(_ n: Int) -> [Int] { + guard 1 <= n else { return [0] } + + var dp = [Int](repeating: 0, count: n + 1) + for num in 1...n { + dp[num] = dp[num >> 1] + (num & 1) + } + + return dp + } +} + +let solution = Solution() +print(solution.solve_4(0)) diff --git a/encode-and-decode-strings/EGON.swift b/encode-and-decode-strings/EGON.swift new file mode 100644 index 000000000..c5410dcac --- /dev/null +++ b/encode-and-decode-strings/EGON.swift @@ -0,0 +1,68 @@ +import Foundation + +class Solution { + static let DELIMITER = "," + + /* ASCII 풀이 */ + static let ASCII_STR_LENGTH = 3 + + func encodeWithASCII(strs: [String]) -> String { + return strs.map { (str) in + str.compactMap { (char) in + guard let asciiValue = char.asciiValue else { + return nil + } + + let asciiStr = String(asciiValue) + + return String( + repeating: "0", + count: Solution.ASCII_STR_LENGTH - asciiStr.count + ) + asciiStr + }.reduce("") { (acc, cur) in acc + cur } + } + .joined(separator: Solution.DELIMITER) + } + + func decodeWithASCII(str: String) -> [String] { + return str.components(separatedBy: Solution.DELIMITER) + .map { (encodedStr) in + return stride(from: 0, to: encodedStr.count, by: Solution.ASCII_STR_LENGTH) + .compactMap { i in + let startIndex = String.Index(utf16Offset: i, in: encodedStr) + let endIndex = String.Index(utf16Offset: i + Solution.ASCII_STR_LENGTH, in: encodedStr) + let asciiValue = UInt8(encodedStr[startIndex.. String { + return strs.compactMap { (str) in + if let data = str.data(using: .utf8) { + return data.base64EncodedString() + } else { + return nil + } + }.joined(separator: Solution.DELIMITER) + } + + func decodeWithBASE64(str: String) -> [String] { + return str.components(separatedBy: Solution.DELIMITER) + .compactMap { (encodedStr) in + if let data = Data(base64Encoded: encodedStr) { + return String(data: data, encoding: .utf8) + } else { + return nil + } + } + } +} + +let solution = Solution() +let strs = ["lint", "code", "love", "you"] +let encoded = solution.encodeWithBASE64(strs: strs) +print(encoded) +let decoded = solution.decodeWithBASE64(str: encoded) +print(decoded) diff --git a/valid-anagram/EGON.swift b/valid-anagram/EGON.swift new file mode 100644 index 000000000..bc12b1c69 --- /dev/null +++ b/valid-anagram/EGON.swift @@ -0,0 +1,34 @@ +class Solution { + + /* + Runtime: 16 ms (Beats 84.96%) + Time Complexity: O(n) + - 길이가 n인 str s, str t, dict counter를 순회하므로 O(3n) ~= O(n) + Space Complexity: O(n) + - 크기가 최대 n인 dict를 변수로 저장하여 사용하므로 O(n) + Memory: 16.01 MB (Beats 97.18%) + */ + func isAnagram(_ s: String, _ t: String) -> Bool { + var countDict: [String.Element: Int] = [:] + + for char in s { + countDict[char] = (countDict[char] ?? 0) + 1 + } + + for char in t { + guard let count = countDict[char] else { + return false + } + + countDict[char] = count - 1 + } + + for count in countDict.values { + if count != 0 { + return false + } + } + + return true + } +} From 816ec49cc5a7f0912812f13bc7c26cef02b7e598 Mon Sep 17 00:00:00 2001 From: "changmuk.im" Date: Sat, 24 Aug 2024 23:30:06 +0900 Subject: [PATCH 3/3] edit : add missing EOF line --- decode-ways/EGON.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/decode-ways/EGON.py b/decode-ways/EGON.py index 44beb1d99..afbea7c8d 100644 --- a/decode-ways/EGON.py +++ b/decode-ways/EGON.py @@ -62,4 +62,4 @@ def test_3(self): if __name__ == '__main__': - main() \ No newline at end of file + main()