Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions next_permutation/phase1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
if len(nums) == 1:
return

pivot_index = len(nums) - 2 # 比較の中心となるindexを定義
while pivot_index > -1 and nums[pivot_index] >= nums[pivot_index+1]:
pivot_index -= 1

if pivot_index == -1:
nums.reverse()
return

swap_index = len(nums) - 1 # swapに使うindexを定義
while nums[swap_index] <= nums[pivot_index]:
swap_index -= 1

nums[swap_index], nums[pivot_index] = nums[pivot_index], nums[swap_index]

nums[pivot_index+1:] = reversed(nums[pivot_index+1:])
return
48 changes: 48 additions & 0 deletions next_permutation/phase2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def _find_pivot_index(nums: List[int])->int:
# 比較の中心となるindexを定義
# 末端から見ていって増加関係のないところを比較indexとする
pivot_index = len(nums) - 2
while pivot_index > -1 and nums[pivot_index] >= nums[pivot_index+1]:
pivot_index -= 1
return pivot_index

def _find_swap_index(nums: List[int], pivot_index: int)->int:
# swapに使うindexを定義
# swapする位置のindexを求める
swap_index = len(nums) - 1
while nums[swap_index] <= nums[pivot_index]:
swap_index -= 1
return swap_index

if len(nums) == 1:
return

pivot_index = _find_pivot_index(nums)

if pivot_index == -1:
nums.reverse()
return

swap_index = _find_swap_index(nums, pivot_index)

nums[swap_index], nums[pivot_index] = nums[pivot_index], nums[swap_index]

nums[pivot_index+1:] = reversed(nums[pivot_index+1:])
return

"""
None型を返すせいで, 正直PythonよりはC++とかの方が書きやすいと感じたが, とりあえずPythonで書く練習をした

Reference:
https://github.com/shining-ai/leetcode/pull/58/files 解くことに夢中になりすぎて関数での分割を忘れていた。
nums[pivot_index+1:] = reversed(nums[pivot_index+1:])よりもnums[left + 1 :] = sorted(nums[left + 1 :])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[]内の演算子の周りにスペースを入れるか入れないかはPEPではどうなっていますか?少なくとも一貫性のある書き方にはしてほしいです。

の方が認知コストは低いなあと感じた。reversedで良いことは紙とペンで確かめられるけど, それをしなきゃいけない感じのコードなら確かに書くべきではないのかも

https://github.com/hayashi-ay/leetcode/pull/67/files
markdownに書いてあるNext Permutationアルゴリズムの説明がわかりやすいと思いました。あとコメントにあった通り次から関数名は動詞から書き始めることを意識してみます。
"""
35 changes: 35 additions & 0 deletions next_permutation/phase3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class Solution:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pivot_indexswap_indexをコメントで定義して、使うのもありだと思います。

def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def _find_pivot_index(nums: List[int])->int:
# 比較の対象となる数のindexを見つける
pivot_index = len(nums) - 2
while pivot_index > -1 and nums[pivot_index] >= nums[pivot_index+1]:
pivot_index -= 1
return pivot_index

def _find_swap_index(nums: List[int], pivot_index: int)->int:
# 後ろからnums[pivot_index]より大きい数を見つけてswapするindexを取り出す
swap_index = len(nums) - 1
while nums[swap_index] <= nums[pivot_index]:
swap_index -= 1
return swap_index

if len(nums) == 1:
return

pivot_index = _find_pivot_index(nums)

if pivot_index == -1:
nums.reverse()
return

swap_index = _find_swap_index(nums, pivot_index)

nums[swap_index], nums[pivot_index] = nums[pivot_index], nums[swap_index]

nums[pivot_index+1:] = sorted(nums[pivot_index+1:])

return nums
35 changes: 35 additions & 0 deletions next_permutation/phase4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def _find_first_not_sorted_index(nums: List[int])->int:
# 後ろから走査し, nums[index] >= nums[index+1]ではなくなる初めてのindexを取り出す
index = len(nums) - 2
while index > -1 and nums[index] >= nums[index+1]:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

index > -1 よりindex >= 0の方が分かりやすい気がします。

index -= 1
return index

def _find_second_largest_index(nums: List[int], compare_index: int)->int:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

second largestは2番目に大きい数なので適切な表現ではないと思います。
rfind_bigger_than(num)なんかでどうでしょう。

numsは引数に含める必要はありません。

# 後ろからnums[compare_index]より大きい数を見つけてswapするindexを取り出す
index = len(nums) - 1
while nums[index] <= nums[compare_index]:
index -= 1
return index

if len(nums) == 1:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

長さ1は特別扱いが必要ですか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

index = len(nums) - 2でindex = -1となるので不要でした

return

left = _find_first_not_sorted_index(nums)

if left == -1:
nums.reverse()
return

right = _find_second_largest_index(nums, left)

nums[right], nums[left] = nums[left], nums[right]

nums[left+1:] = sorted(nums[left+1:])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

降順にソートされているので、reverseすればいいです。コピーするより、in-placeの方の関数を使った方がいいでしょう。


return nums
27 changes: 27 additions & 0 deletions next_permutation/phase5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def _find_first_not_sorted_index() -> int:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_rfind_bigger_thanに合わせるならこちら_rfind_first_not_sorted_indexじゃないですか?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not_sortedよりnot_decreasingの方がより関数内の処理が具体化されると思います。

index = len(nums) - 2
while index >= 0 and nums[index] >= nums[index+1]:
index -= 1
return index

def _rfind_bigger_than(compare_index: int) -> int:
index = len(nums) - 1
while nums[index] <= nums[compare_index]:
index -= 1
return index

left = _find_first_not_sorted_index()

if left == -1:
nums.reverse()
return

right = _rfind_bigger_than(left)
nums[left], nums[right] = nums[right], nums[left]
nums[left+1:].reverse()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

たぶんこの部分意図した挙動になっていないと思います。

Pythonのsliceは新しいリストを作ります。
https://www.reddit.com/r/Python/comments/rfm6ph/does_array_slicing_use_extra_memory/
https://github.com/python/cpython/blob/a62be77266b1beadd42d4952186332bc0847b7d6/Objects/listobject.c#L465

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

知らなかったです。あと多分leetcodeでテストしたつもりになっていましたが多分し忘れていました。今in-place処理にしたphase6を追加してみました。

return
33 changes: 33 additions & 0 deletions next_permutation/phase6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def _rfind_first_not_decreasing_index() -> int:
index = len(nums) - 2
while index >= 0 and nums[index] >= nums[index+1]:
index -= 1
return index

def _rfind_bigger_than(compare_index: int) -> int:
index = len(nums) - 1
while nums[index] <= nums[compare_index]:
index -= 1
return index

left = _rfind_first_not_decreasing_index()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

全体的にちょっと空行多めかしら。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

19行目の空行だけ余分な気がします。23と26はあってもなくても良さそうな感じですかね。


if left == -1:
nums.reverse()
return

right = _rfind_bigger_than(left)
nums[left], nums[right] = nums[right], nums[left]

swap_right = len(nums) - 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

関数に切り出しても良いですね。このままでも良いとは思います。

swap_left = left + 1
while swap_left < swap_right:
nums[swap_right], nums[swap_left] = nums[swap_left], nums[swap_right]
swap_left += 1
swap_right -= 1
return
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最後のreturnはなくても挙動は変わらないですね。

31 changes: 31 additions & 0 deletions next_permutation/phase7.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def _rfind_first_not_decreasing_index() -> int:
index = len(nums) - 2
while index >= 0 and nums[index] >= nums[index+1]:
index -= 1
return index

def _rfind_bigger_than(compare_index: int) -> int:
index = len(nums) - 1
while nums[index] <= nums[compare_index]:
index -= 1
return index

left = _rfind_first_not_decreasing_index()
if left == -1:
nums.reverse()
return

right = _rfind_bigger_than(left)
nums[left], nums[right] = nums[right], nums[left]
swap_left = left + 1
swap_right = len(nums) - 1
# in-place reverse
while swap_left < swap_right:
nums[swap_left], nums[swap_right] = nums[swap_right], nums[swap_left]
swap_left += 1
swap_right -= 1