diff --git a/arai60/two-sum/README.md b/arai60/two-sum/README.md new file mode 100644 index 0000000..7281ab1 --- /dev/null +++ b/arai60/two-sum/README.md @@ -0,0 +1,45 @@ +## 考察 +- 過去に何度も解いたことあり +- 方針は4つ思い浮かぶ + - 全探索 + - C(n, 2)パターンを全部調べる + - 今回はこの方針はスキップ + - time: O(n^2), space: O(1) + - ハッシュマップ + - 追加のメモリを使用する + - 足し算が可換(答えの順番が関係ない)ので1パスでOK + - 引き算とかだとおそらく1パスではできない + - time: O(n), space: O(n) + - ソートして二分探索 + - ソートしたら二分探索可能 + - time: O(n log n), space: O(1) -> space: O(1)は勘違いだった。元のインデックスを保持する必要があるので、正しくはO(n) + - ソートして2 pointers + - メモリO(1)の解法では、最速になると思う + - ソートがボトルネックになる + - time: O(n lon n), space: O(1) -> space: O(1)は勘違いだった。元のインデックスを保持する必要があるので、正しくはO(n) + +- ハッシュマップを使った手法を選択 +- あとは実装 + +## Step1 +- ハッシュマップを使った方法を実装 +- time: O(n), space: O(n) + +## Step2 +- 2 pointersの手法でもやってみる +- ソートするとインデックスが変わるのでそこだけ注意した +- time: O(n log n), space: O(1) + +## Step3 +- ハッシュマップを使った方法で実装 +- 1回目: 1m02s +- 2回目: 55s +- 3回目: 47s + +## Step4 +- レビューを元に修正 +- 変数名を変更 + - complement -> complement_value +- Exceptionにメッセージを付与 + - 呼び出し元に対して親切に +- enumerateを使ってみた diff --git a/arai60/two-sum/step1.py b/arai60/two-sum/step1.py new file mode 100644 index 0000000..ad15a37 --- /dev/null +++ b/arai60/two-sum/step1.py @@ -0,0 +1,11 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + n = len(nums) + num_to_index = {} + for i in range(n): + complement = target - nums[i] + if complement in num_to_index: + return [i, num_to_index[complement]] + num_to_index[nums[i]] = i + + raise Exception() diff --git a/arai60/two-sum/step2.py b/arai60/two-sum/step2.py new file mode 100644 index 0000000..4b63061 --- /dev/null +++ b/arai60/two-sum/step2.py @@ -0,0 +1,20 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + n = len(nums) + nums_with_index = [(nums[i], i) for i in range(n)] + nums_with_index.sort() + + left = 0 + right = n - 1 + while left < right: + num_left, index_left = nums_with_index[left] + num_right, index_right = nums_with_index[right] + sum_ = num_left + num_right + if sum_ == target: + return [index_left, index_right] + if sum_ < target: + left += 1 + else: + right -= 1 + + raise Exception() diff --git a/arai60/two-sum/step3.py b/arai60/two-sum/step3.py new file mode 100644 index 0000000..ad15a37 --- /dev/null +++ b/arai60/two-sum/step3.py @@ -0,0 +1,11 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + n = len(nums) + num_to_index = {} + for i in range(n): + complement = target - nums[i] + if complement in num_to_index: + return [i, num_to_index[complement]] + num_to_index[nums[i]] = i + + raise Exception() diff --git a/arai60/two-sum/step4.py b/arai60/two-sum/step4.py new file mode 100644 index 0000000..bd4e58d --- /dev/null +++ b/arai60/two-sum/step4.py @@ -0,0 +1,10 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_to_index = {} + for i, num in enumerate(nums): + complement_value = target - num + if complement_value in num_to_index: + return [i, num_to_index[complement_value]] + num_to_index[num] = i + + raise Exception('unreachable')