Skip to content

46. Permutations - #44

Open
akmhmgc wants to merge 1 commit into
mainfrom
46
Open

46. Permutations#44
akmhmgc wants to merge 1 commit into
mainfrom
46

Conversation

@akmhmgc

@akmhmgc akmhmgc commented Oct 5, 2025

Copy link
Copy Markdown
Owner

解いた問題

46. Permutations

使用言語

Ruby

次に解く問題

78. Subsets

@akmhmgc akmhmgc added the ruby label Oct 5, 2025
Comment thread 46/step2.md
end
permute_helper.call(nums)
end
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

はじめに読んだ時、lambda がネストされていて難しく感じました。nums はブロックパラメータに書かなくても読めるはずなので書かれているのはなんでだろうと思いました。処理を読むと append_permutes の nums はまだ追加していない nums であり、ブロックパラメータに書く必要があるとわかりました。また、permute_helper は入出力が permute と同じなのでまとめられないかなと思いました。自分だったら以下のように書くと思います。

def permute(nums)
    results = []
    permute_helper = lambda do |permuted_prefix, remaining_nums|
        if remaining_nums.empty?
            results << permuted_prefix
            return
        end
        remaining_nums.each_with_index do |num, i|
            new_permuted_prefix = permuted_prefix + [num]
            new_remaining_nums = remaining_nums[0...i] + remaining_nums[(i + 1)..-1]
            permute_helper.call(new_permuted_prefix, new_remaining_nums)
        end
    end
    permute_helper.call([], nums)
    results
end

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.

コメントありがとうございます。
おっしゃる通りlambdaの引数として利用しているnumsが関数の引数の名前と同じでかなり読みにくいですね。
あと外側のlambdaには引数は不要ですね。

個人的にはresultsをlambdaの外のものを変更するのがあまり好きではないので以下のように書こうと思います。

# @param {Integer[]} nums
# @return {Integer[][]}
def permute(nums)
    permute_helper = lambda do
        permutes = []
        append_permutes = lambda do |permute, remaining_nums|
            if remaining_nums.empty?
                permutes << permute 
                return
            end
            remaining_nums.each_with_index do |num, i|
                new_permute = permute + [num]
                new_nums = remaining_nums[0...i] + remaining_nums[(i + 1)..-1]
                append_permutes.call(new_permute, new_nums)
            end
        end
        append_permutes.call([], nums)
        permutes
    end
    permute_helper.call
end

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.

少し考えたのですが、この程度であればlambdaはネストさせなくても良い気がしてきました。
permute内に処理が追加されるようなら検討しても良いかもしれません。(その時はlamdaをネストさせるより別のメソッドに切り出すかもしれないですが)

Comment thread 46/step3.md
def permute(nums)
permutes = [[]]
while permutes.first.size != nums.size
permutes = permutes.each_with_object([]) do |permute, next_permutes|

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

細かいですが、permuteは動詞の印象があるので、この辺の変数の名前はpermutationsやpermsにしたいかもしれません。

Comment thread 46/step3.md
permutes = [[]]
while permutes.first.size != nums.size
permutes = permutes.each_with_object([]) do |permute, next_permutes|
next_permutes.concat((nums - permute).map { |num| permute + [num] })

@potrue potrue Oct 5, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらのやり方はこちらのやり方で読みやすいと思いますが、割と広く知られている手法としては、次のようなバックトラッキングを用いたやり方で順列を生成するアルゴリズムがあると思います。
(LLMに書かせたコードなので読みにくかったらすみません)

def permute_inplace(nums)
  res = []

  backtrack = ->(first) do
    if first == nums.length
      res << nums.dup
      return
    end

    (first...nums.length).each do |i|
      nums[first], nums[i] = nums[i], nums[first]
      backtrack.call(first + 1)
      nums[first], nums[i] = nums[i], nums[first]  # 元に戻す
    end
  end

  backtrack.call(0)
  res
end

どこまで作ったかのindexを渡すことで、途中まで作った順列を表す配列それ自体にnums - permuteを含めることができるというのと、各要素の各段階において新しい配列を作る必要がない、という部分で多少効率的かと思います。

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.

ありがとうございます!
発想にまだ慣れていないですがコード自体は読みやすいです。

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants