diff --git a/1. Two Sum.md b/1. Two Sum.md new file mode 100644 index 0000000..c3567f8 --- /dev/null +++ b/1. Two Sum.md @@ -0,0 +1,130 @@ +# step 1 +解くこと自体は簡単だった。 + +与えられた数値を持つindexを`num_to_index`にいれて記録したが、同じ値があった場合、後からでた +もののindexしか記録しない様になっている。全ての組み合わせを出せとかだとうまくいかない。 + +条件を満たす組がちょうど一つしか存在しないという仮定があったためこの様にした。この仮定のもとで +わざわざ`num_to_indices`とかにするのも不必要に複雑かと判断した。 + +条件を満たす組がない場合、Noneを返すか、例外を発生させるか迷った。 +type annotation的に後者のほうがいいと判断した。 + +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_to_index = dict() + for i in range(len(nums)): + rest = target - nums[i] + if rest in num_to_index: + return [num_to_index[rest], i] + + num_to_index[nums[i]] = i + + raise RuntimeError( + f"No pair found in twoSum(): nums = {nums}, target = {target}" + ) +``` +# step 2 +- https://github.com/katataku/leetcode/pull/10/files + - 入力をsortして、両端から調べていく解法もある + - `for i, num in enumerate(nums):`使っていた。`range(len(nums))`よりも簡潔(関数呼び出しの数が少なく)でよさそう +- https://github.com/haniwachann/leetcode/pull/2 + - `for (int i = 0; i < nums.size() - 1; i++)`で-1しない考えもある。空のループが回るだけだから。 + - ボトルネックでないところは、最適化するなを思い出した。 +- https://github.com/philip82148/leetcode-arai60/pull/1 + - 実際にsortしている手法 + +sortして端から抑えていく + +`n = nums.length`として、 +- time complexity: O(n log(n)) +- space complexity: O(n) +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_index_pairs = [] + for i, num in enumerate(nums): + num_index_pairs.append((num, i)) + num_index_pairs.sort() + + left = 0 + right = len(nums) - 1 + while left < right: + two_sum = num_index_pairs[left][0] + num_index_pairs[right][0] + if two_sum == target: + return [num_index_pairs[left][1], num_index_pairs[right][1]] + + if two_sum > target: + right -= 1 + else: + left += 1 + + raise RuntimeError( + f"No pair found in twoSum(): nums = {nums}, target = {target}" + ) +``` + +hash tableを使った解法 +`n = nums.length`として、 +- time complexity: O(n) +- space complexity: O(n) +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_to_index = dict() + for i, num in enumerate(nums): + rest = target - num + if rest in num_to_index: + return [num_to_index[rest], i] + + num_to_index[num] = i + + raise RuntimeError( + f"twoSum(): No pair found: nums = {nums}, target = {target}" + ) +``` + +# step 3 + +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_to_index = dict() + for i, num in enumerate(nums): + rest_value = target - num + if rest_value in num_to_index: + return [num_to_index[rest_value], i] + + num_to_index[num] = i + raise RuntimeError( + f"twoSum(): No pair found: nums = {nums}, target = {target}" + ) +``` + +# step 4 +コメントまとめ +- このシチュエーションならRuntimeErrorかなとおもったが、odaさん・hayashiさんはValueErrorを挙げていた。自分の感覚が少しずれていそうだった。 + - RuntimeError: Raised when an error is detected that doesn’t fall in any of the other categories. The associated value is a string indicating what precisely went wrong. + - ValueError: Raised when an operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception such as IndexError. + - RuntimeErrorは相当強い条件の中で使うもので、ValueErrorにおける、an inappropriate valueの解釈は自分の想定していたより広くとって良さそう +- dict()と{}が異なる。 + - https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/use-dict-literal.html + - https://madebyme.today/blog/python-dict-vs-curly-brackets/ + - わかりやすくていい記事だった。 + +restからcomplementに変更した。 +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + num_to_index = {} + for i, num in enumerate(nums): + complement = target - num + if complement in num_to_index: + return [num_to_index[complement], i] + num_to_index[num] = i + raise ValueError( + "twoSum(): No pair found: " + f"nums = {nums}, target = {target}" + ) +``` \ No newline at end of file