From 6eff8213ad65234355de3e42e10cf78d72a39ddd Mon Sep 17 00:00:00 2001 From: mike <59136831+Mike0121@users.noreply.github.com> Date: Sun, 12 May 2024 22:47:51 +0900 Subject: [PATCH 1/5] Create 46. Permutations.md https://leetcode.com/problems/permutations/description/ --- .../46. Permutations.md" | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 "\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" new file mode 100644 index 0000000..07af36f --- /dev/null +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" @@ -0,0 +1,147 @@ +## swapによる解答 +--- +### 1回目 +そもそも手作業でどう解くべきかがピンと来ず、解けなかった。 +自身で手作業で書き出していく中で、入れ替えを複数行えば良いことに気がついたが、 +本番解けるかはかなり微妙。 + + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + ''' + bt(0) + ├─ bt(1) + │ ├─ bt(2) # nums = [1, 2, 3] + │ └─ bt(2) # nums = [1, 3, 2] (2と3を入れ替え) + ├─ bt(1) + │ ├─ bt(2) # nums = [2, 1, 3] (1と2を入れ替え) + │ └─ bt(2) # nums = [2, 3, 1] (1と3を入れ替え) + └─ bt(1) + ├─ bt(2) # nums = [3, 2, 1] (1と3を入れ替え、その後2と3を入れ替え) + └─ bt(2) # nums = [3, 1, 2] (1と3を入れ替え) + ''' + + all_combinations = [] + + def find_all_permutation(i): + if i == len(nums): + all_combinations.append(nums[:]) + return + print(f"bt({i})") + for j in range(i, len(nums)): + nums[i], nums[j] = nums[j], nums[i] + find_all_permutation(i + 1) + nums[j], nums[i] = nums[i], nums[j] + + find_all_permutation(0) + return all_combinations +``` + + +### 2~3回目 +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + all_permutations = [] + + def find_all_permutation(i): + if i == len(nums): + all_permutations.append(nums[:]) + return + for j in range(i, len(nums)): + nums[i], nums[j] = nums[j], nums[i] + find_all_permutation(i + 1) + nums[j], nums[i] = nums[i], nums[j] + + find_all_permutation(0) + return all_permutations +``` + +## push,popを用いた解答 +--- + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + all_permutations = [] + + def find_all_permutations(permutation): + if len(permutation) == len(nums): + all_permutations.append(permutation[:]) + + for num in nums: + if num not in permutation: + permutation.append(num) + find_all_permutations(permutation) + permutation.pop() + + + find_all_permutations([]) + return all_permutations +``` + + +## stackを用いた解答 +--- + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + all_permutations = [] + permutation_and_remain = [([], nums)] + + while permutation_and_remain: + permutation, remain = permutation_and_remain.pop() + + if len(permutation) == len(nums): + all_permutations.append(permutation) + continue + + for i, num in enumerate(remain): + permutation_and_remain.append((permutation + [num], remain[:i] + remain[i+1:])) + + return all_permutations +``` + + + +## モジュールを用いた解答 +--- +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + return [permutation for permutation in itertools.permutations(nums)] +``` + +https://docs.python.org/3/library/itertools.html#itertools.permutations + +itertools permutationsの内部実装再現 (documentより) +```python +def permutations(iterable, r=None): + # permutations('ABCD', 2) → AB AC AD BA BC BD CA CB CD DA DB DC + # permutations(range(3)) → 012 021 102 120 201 210 + pool = tuple(iterable) + n = len(pool) + r = n if r is None else r + if r > n: + return + indices = list(range(n)) + cycles = list(range(n, n-r, -1)) + yield tuple(pool[i] for i in indices[:r]) + while n: + for i in reversed(range(r)): + cycles[i] -= 1 + if cycles[i] == 0: + indices[i:] = indices[i+1:] + indices[i:i+1] + cycles[i] = n - i + else: + j = cycles[i] + indices[i], indices[-j] = indices[-j], indices[i] + yield tuple(pool[i] for i in indices[:r]) + break + else: + return +``` + + From 30d2c97a23d643eba2206f8bc81543e7954117a2 Mon Sep 17 00:00:00 2001 From: mike <59136831+Mike0121@users.noreply.github.com> Date: Wed, 15 May 2024 00:35:20 +0900 Subject: [PATCH 2/5] Update 46. Permutations.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit デバッグのprint文を削除 各アルゴリズムに時間計算量・空間計算量を追記 標準ライブラリによる解答の返り値をList[List[int]]にするコードを追記 --- .../46. Permutations.md" | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" index 07af36f..69faa3d 100644 --- "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" @@ -1,11 +1,12 @@ ## swapによる解答 --- ### 1回目 +時間計算量: O(N\*N!) (リストのコピー\*再帰)
+空間計算量: O(N\*N!)
そもそも手作業でどう解くべきかがピンと来ず、解けなかった。 自身で手作業で書き出していく中で、入れ替えを複数行えば良いことに気がついたが、 本番解けるかはかなり微妙。 - ```python class Solution: def permute(self, nums: List[int]) -> List[List[int]]: @@ -28,7 +29,6 @@ class Solution: if i == len(nums): all_combinations.append(nums[:]) return - print(f"bt({i})") for j in range(i, len(nums)): nums[i], nums[j] = nums[j], nums[i] find_all_permutation(i + 1) @@ -40,6 +40,8 @@ class Solution: ### 2~3回目 +時間計算量: 1回目と同じ
+空間計算量: 1回目と同じ
```python class Solution: def permute(self, nums: List[int]) -> List[List[int]]: @@ -60,6 +62,8 @@ class Solution: ## push,popを用いた解答 --- +時間計算量: O(N\*N\*N!) (リストのコピー\*配列探索(if文)\*再帰)
+空間計算量: O(N\*N!)
```python class Solution: @@ -81,9 +85,10 @@ class Solution: return all_permutations ``` - ## stackを用いた解答 --- +時間計算量: O(N\*N\*N!) (numsの長さ\*remainのスライスの作成\*while(スタックが空になるまで))
+空間計算量: O(N\*N!)
```python class Solution: @@ -104,16 +109,26 @@ class Solution: return all_permutations ``` +## ~モジュール~ 標準ライブラリを用いた解答 +--- +時間計算量: O(N\*N!) (listへの変換\*permutation)
+空間計算量: O(N\*N!)
-## モジュールを用いた解答 ---- ```python class Solution: def permute(self, nums: List[int]) -> List[List[int]]: return [permutation for permutation in itertools.permutations(nums)] ``` +List[List[int]]を返すように修正 +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + return [list(permutation) for permutation in permutations(nums)] +``` + + https://docs.python.org/3/library/itertools.html#itertools.permutations itertools permutationsの内部実装再現 (documentより) From 438f3bbef519ba07d97b6a76c60a79bce1bf9c47 Mon Sep 17 00:00:00 2001 From: mike <59136831+Mike0121@users.noreply.github.com> Date: Sat, 18 May 2024 17:01:56 +0900 Subject: [PATCH 3/5] Update 46. Permutations.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit numsをin-placeで書き換える解法を追記 --- .../46. Permutations.md" | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" index 69faa3d..884c44d 100644 --- "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" @@ -1,3 +1,34 @@ +## numsをin-placeで書き換える解法 + +時間計算量: O(N\*N!)
+空間計算量: O(N\*N!)
+ +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + result = [] + nums.sort() + nums_permute = nums.copy() + result.append(nums_permute[:]) + + while True: + pivot = len(nums_permute) - 2 + while pivot >= 0 and nums_permute[pivot] >= nums_permute[pivot + 1]: + pivot -= 1 + if pivot == -1: + return result + + swap = len(nums_permute) - 1 + while nums_permute[pivot] >= nums_permute[swap]: + swap -= 1 + + nums_permute[pivot], nums_permute[swap] = nums_permute[swap], nums_permute[pivot] + + nums_permute[pivot+1:] = nums_permute[pivot+1:][::-1] + result.append(nums_permute[:]) +``` + + ## swapによる解答 --- ### 1回目 @@ -79,7 +110,6 @@ class Solution: permutation.append(num) find_all_permutations(permutation) permutation.pop() - find_all_permutations([]) return all_permutations @@ -159,4 +189,6 @@ def permutations(iterable, r=None): return ``` + + From 3a7fe4fe6a3bc2d266aa5d3fae5a6797e6f505b3 Mon Sep 17 00:00:00 2001 From: mike <59136831+Mike0121@users.noreply.github.com> Date: Mon, 20 May 2024 23:59:07 +0900 Subject: [PATCH 4/5] Update 46. Permutations.md --- .../46. Permutations.md" | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" index 884c44d..f3fce82 100644 --- "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/46. Permutations.md" @@ -1,4 +1,4 @@ -## numsをin-placeで書き換える解法 +## numsをin-placeで書き換える解法 ★ 時間計算量: O(N\*N!)
空間計算量: O(N\*N!)
@@ -29,7 +29,7 @@ class Solution: ``` -## swapによる解答 +## swapによる解答 ★ --- ### 1回目 時間計算量: O(N\*N!) (リストのコピー\*再帰)
@@ -91,7 +91,7 @@ class Solution: return all_permutations ``` -## push,popを用いた解答 +## append,popを用いた解答 (非最適解) --- 時間計算量: O(N\*N\*N!) (リストのコピー\*配列探索(if文)\*再帰)
空間計算量: O(N\*N!)
@@ -115,7 +115,46 @@ class Solution: return all_permutations ``` -## stackを用いた解答 +(変数を減らしたver) +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + all_permutations = [] + + def find_all_permutations(permutation): + if len(permutation) == len(nums): + all_permutations.append(permutation) + + for num in nums: + if num not in permutation: + find_all_permutations(permutation + [num]) + + find_all_permutations([]) + return all_permutations +``` + +(setを利用した最適化)★ +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + unique_nums = set(nums) + all_permutations = [] + + def find_all_permutations(permutation): + if len(permutation) == len(nums): + all_permutations.append(permutation) + + remain_nums = list(unique_nums) + for num in remain_nums: + unique_nums.remove(num) + find_all_permutations(permutation + [num]) + unique_nums.add(num) + + find_all_permutations([]) + return all_permutations +``` + +## stackを用いた解答 ★ --- 時間計算量: O(N\*N\*N!) (numsの長さ\*remainのスライスの作成\*while(スタックが空になるまで))
空間計算量: O(N\*N!)
From b482a38e65a8591bbbf17e732dbc59bc06cf36ab Mon Sep 17 00:00:00 2001 From: mike <59136831+Mike0121@users.noreply.github.com> Date: Tue, 21 May 2024 19:06:46 +0900 Subject: [PATCH 5/5] Create 50. Pow(x, n).md https://leetcode.com/problems/powx-n/description/ --- .../50. Pow(x, n).md" | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 "\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/50. Pow(x, n).md" diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/50. Pow(x, n).md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/50. Pow(x, n).md" new file mode 100644 index 0000000..35840d6 --- /dev/null +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/50. Pow(x, n).md" @@ -0,0 +1,97 @@ +``` +負の数の割り算と余り、言語によって振る舞いが色々なので自分の使い慣れたものについては覚えておきましょう。 +``` + +## 計算式による解法 +--- +時間計算量: O(1)
+空間計算量: O(1)
+```python +class Solution: + def myPow(self, x: float, n: int) -> float: + return float(x ** n) +``` + +## 再帰による解法 (maximum recursion depth exceeded) +--- + +### 1回目 +時間計算量: O(N)
+空間計算量: O(N)
+よく考えたら、```if n == 1: return x```は不要。 +また、n == -1 は、最初にnが正負かで値の更新を行った方が、わかりやすい。 +(2回目以降で反映。) + +```python +class Solution: + def myPow(self, x: float, n: int) -> float: + if n == 0: + return 1 + if n == 1: + return x + if n == -1: + return 1 / x + + return x * self.myPow(x, n - 1) if n > 0 else 1 / x * self.myPow(x, n + 1) +``` + +### 2回目 +時間計算量: O(logN)
+空間計算量: O(logN)
+ +分割統治法のイメージで書いたが、直感的に何をしているのかわかづらい。 +```python +class Solution: + def myPow(self, x: float, n: int) -> float: + if n == 0: + return 1 + if n < 0: + x = 1 / x + n *= -1 + + divided_prod = self.myPow(x, n // 2) + if n % 2 == 0: + return divided_prod * divided_prod + else: + return divided_prod * divided_prod * x +``` + +### 3回目 +時間計算量: O(logN)
+空間計算量: O(logN)
+```python +class Solution: + def myPow(self, x: float, n: int) -> float: + if n == 0: + return 1 + if n < 0: + x = 1 /x + n *= -1 + if n % 2 == 0: + return self.myPow(x * x, n // 2) + else: + return x * self.myPow(x * x, n // 2) +``` + + + +## Interationによる解法 +--- +時間計算量: O(logN)
+空間計算量: O(logN)
+```python +class Solution: + def myPow(self, x: float, n: int) -> float: + if n < 0: + x = 1 /x + n *= -1 + + accumulated_prod = 1 + while n > 0: + if n % 2 != 0: + accumulated_prod *= x + x *= x + n //= 2 + + return accumulated_prod +```