Skip to content

Conversation

@Satorien
Copy link
Owner

if num in permuted_nums:
continue
permutations += permute_helper(permuted_nums + [num])
return permutations if permutations else [permuted_nums]
Copy link

Choose a reason for hiding this comment

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

これ、[permuted_nums] をここに持ってくるのは意味がだいぶ違うので個人的にはあまり好きではないですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

確かに意味としては直感的ではないですね。少し迷って短く書いてみたんですが微妙でした

permutations = []
for i in range(len(nums)):
prefix = [nums[i]]
sub_permutations = self.permute(nums[:i]+nums[i+1:])
Copy link

Choose a reason for hiding this comment

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

個人的には + の両側にスペースを空けたいです。

参考までに、関連するスタイルガイドを共有いたします。

https://peps.python.org/pep-0008/#other-recommendations

Always surround these binary operators with a single space on either side: assignment (=), augmented assignment (+=, -= etc.), comparisons (==, <, >, !=, <=, >=, in, not in, is, is not), Booleans (and, or, not).

https://google.github.io/styleguide/pyguide.html#36-whitespace

Surround binary operators with a single space on either side for assignment (=), comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), and Booleans (and, or, not). Use your better judgment for the insertion of spaces around arithmetic operators (+, -, *, /, //, %, **, @).

なお、これらのスタイルガイドは唯一絶対のルールではなく、数あるガイドラインの一つに過ぎません。チームによって重視する書き方が異なる場合もあります。
そのため、ご自身の中に基準を持ちつつも、最終的にはチーム内で一般的とされる書き方に寄せていくことをお勧めいたします。

Comment on lines +69 to +71
if num in prefix:
continue
permutations += permute_helper(prefix + [num])

Choose a reason for hiding this comment

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

O(n)のスライスは回避していますが、if num in prefix:の判定でprefixはリストなのでO(n)、またprefix + [num]でリストの再構築がO(n)で、結局定数倍最適化の範疇ではありますね。

スライスはネイティブコードで走る部分なので、その定数倍も劇的ではなさそうだと推定します。

関連して、if num in prefix:ですが、bool配列やsetで使用済みを管理するオブジェクトを別に作っておくとO(1)にできそうです。これは同じく定数倍最適化ですが、結構効きそうな感覚があります。

Copy link
Owner Author

Choose a reason for hiding this comment

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

そうですね。スライスをくっつけると2つコピーを作ってから更に新しく作ることになると思うのでそこが忌避感を持っていました。

num in prefixは確かにそうなんですが、prefixが最大でも6なのでハッシュはあまり意味がないだろうという判断です。bool配列はありですね。

- https://github.com/tokuhirat/LeetCode/pull/50/files#r2278840164
- 時間計算量の話は1≤num.lengths≤6では線形の方が速そうというところ
- https://github.com/docto-rin/leetcode/pull/51/files#diff-47cd87d2eeba6169d55b484ea322c16f1a03278b0d29a5b0d00f771aaf816f8bR74-R78
- Backtrackingとも呼ぶらしい?がほぼ同じに見える

Choose a reason for hiding this comment

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

prefix変数として持っているリストオブジェクトを、下のコードでは毎回再構築されていますが、私がbacktrackingと呼んで書いているものは1つのオブジェクトを使い回しているように書かれているはずです。

- 一つずつ残っているリストから数字を取り出して末尾に入れる
- 作成済みの順列と残りのリストをペアで保持して処理していく
- なぜかエラー→next_remaining_nums=remaining_numsにすると参照先をremoveしてしまう
- copy.deepcopyで対応

Choose a reason for hiding this comment

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

deepcopyを使ってないように見えました。
使われているlist.copy()はshallow copyです。要素がmutableのときは動作に注意したいですね。今回のように要素がimmutableのときは、参照が共通でもどうせ変更があれば参照ごと書き換わる(再代入される)ので困らないという理屈です。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。初めはdeepcopyにしていたんですが、shallow copyでも行けることに気が付いたので修正した次第です。コメントは直し忘れていました


### Complexity Analysis

- 時間計算量:O(N*N!)

Choose a reason for hiding this comment

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

出力サイズ自体がN!個で各要素が長さNなので、時間計算量もどうしてもO(N * N!)は越えられなさそうですが、このオーダーでいかに定数倍最適化できるかが本問の工夫のポイントになってくると思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants