Conversation
| if num in permuted_nums: | ||
| continue | ||
| permutations += permute_helper(permuted_nums + [num]) | ||
| return permutations if permutations else [permuted_nums] |
There was a problem hiding this comment.
これ、[permuted_nums] をここに持ってくるのは意味がだいぶ違うので個人的にはあまり好きではないですね。
There was a problem hiding this comment.
確かに意味としては直感的ではないですね。少し迷って短く書いてみたんですが微妙でした
| permutations = [] | ||
| for i in range(len(nums)): | ||
| prefix = [nums[i]] | ||
| sub_permutations = self.permute(nums[:i]+nums[i+1:]) |
There was a problem hiding this comment.
個人的には + の両側にスペースを空けたいです。
参考までに、関連するスタイルガイドを共有いたします。
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 (+, -, *, /, //, %, **, @).
なお、これらのスタイルガイドは唯一絶対のルールではなく、数あるガイドラインの一つに過ぎません。チームによって重視する書き方が異なる場合もあります。
そのため、ご自身の中に基準を持ちつつも、最終的にはチーム内で一般的とされる書き方に寄せていくことをお勧めいたします。
| if num in prefix: | ||
| continue | ||
| permutations += permute_helper(prefix + [num]) |
There was a problem hiding this comment.
O(n)のスライスは回避していますが、if num in prefix:の判定でprefixはリストなのでO(n)、またprefix + [num]でリストの再構築がO(n)で、結局定数倍最適化の範疇ではありますね。
スライスはネイティブコードで走る部分なので、その定数倍も劇的ではなさそうだと推定します。
関連して、if num in prefix:ですが、bool配列やsetで使用済みを管理するオブジェクトを別に作っておくとO(1)にできそうです。これは同じく定数倍最適化ですが、結構効きそうな感覚があります。
There was a problem hiding this comment.
そうですね。スライスをくっつけると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とも呼ぶらしい?がほぼ同じに見える |
There was a problem hiding this comment.
prefix変数として持っているリストオブジェクトを、下のコードでは毎回再構築されていますが、私がbacktrackingと呼んで書いているものは1つのオブジェクトを使い回しているように書かれているはずです。
| - 一つずつ残っているリストから数字を取り出して末尾に入れる | ||
| - 作成済みの順列と残りのリストをペアで保持して処理していく | ||
| - なぜかエラー→next_remaining_nums=remaining_numsにすると参照先をremoveしてしまう | ||
| - copy.deepcopyで対応 |
There was a problem hiding this comment.
deepcopyを使ってないように見えました。
使われているlist.copy()はshallow copyです。要素がmutableのときは動作に注意したいですね。今回のように要素がimmutableのときは、参照が共通でもどうせ変更があれば参照ごと書き換わる(再代入される)ので困らないという理屈です。
There was a problem hiding this comment.
ありがとうございます。初めはdeepcopyにしていたんですが、shallow copyでも行けることに気が付いたので修正した次第です。コメントは直し忘れていました
|
|
||
| ### Complexity Analysis | ||
|
|
||
| - 時間計算量:O(N*N!) |
There was a problem hiding this comment.
出力サイズ自体がN!個で各要素が長さNなので、時間計算量もどうしてもO(N * N!)は越えられなさそうですが、このオーダーでいかに定数倍最適化できるかが本問の工夫のポイントになってくると思います。
問題文:https://leetcode.com/problems/permutations/description/