Skip to content

209. Minimum Size Subarray Sum #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

fhiyo
Copy link
Owner

@fhiyo fhiyo commented Jul 20, 2024

```py
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
cumsum = [0]

Choose a reason for hiding this comment

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

リストなので、cumsums の方が分かりやすいのかなと思いました。
cumsum にした方がいい理由が思い当たりませんでした。)

Comment on lines +53 to +55
if subarray_sum >= target:
min_length = min(min_length, end - begin)
subarray_sum -= nums[begin]

Choose a reason for hiding this comment

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

end == len(nums) の場合に begin を回すための処理かなと思いました。
だとすると、subarray_sum < target してたらもう subarray_sum は小さくなる一方だと思うので、もう引かなくてもいいのかなと思いました。

            if subarray_sum < target:
                break
            min_length = min(min_length, end - begin)
            subarray_sum -= nums[begin]

ただ、begin のループを抜けようとしたらもうひと手間いると思うので、少し流れが違うだけですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

たしかにそう書けますね。ありがとうございます!

Comment on lines +28 to +29
if min_length == len(nums) + 1:
return 0

Choose a reason for hiding this comment

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

このケースは解が存在していないケースかと思います。この問題における解なしというのは sum(nums) < target のケースなので、この関数の一番始めでチェックしておけばそれ以降は解が存在する前提になり複雑度が減りそうです。

またここで判断するケースでも len(nums) + 1 が解なしを意味するというのはぱっと見ではわかりにくいので、math.inf など明らかにおかしいもので初期化しておくとよさそうに思いました。(上記に書いたように解が存在していることをチェックした後であれば min_length = len(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.

math.inf, 型がfloatなのがちょっと気になるんですよね...使うメリットはあるので選択肢としてありだとは思いますが。
sum(nums) < target かを先にチェックするのは、それも手だと思いますがそこでO(n)かかるコストを払うトレードオフをどう見るかですね... (cpythonなので) C実装のsumは速いからいいだろうという考えもまた分かりますが。

Choose a reason for hiding this comment

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

math.inf, 型がfloatなのがちょっと気になるんですよね...使うメリットはあるので選択肢としてありだとは思いますが。

なるほど、たしかに型が異なるのは気になるポイントかもですね。

sum(nums) < target かを先にチェックするのは、それも手だと思いますがそこでO(n)かかるコストを払うトレードオフをどう見るかですね... (cpythonなので) C実装のsumは速いからいいだろうという考えもまた分かりますが。

全体の時間計算量 O(n) を悪化させる修正ではないので、個人的には可読性を優先するかなというコメントでした。(書かれているとおりトレードオフなので、可読性の向上があまりないと感じていたり、少しでも計算を早めたいという状況であれば、選択は変わると思います)

Comment on lines +79 to +82
for end in range(len(cumsum)):
while cumsum[end] - cumsum[begin] >= target:
min_length = min(min_length, end - begin)
begin += 1

Choose a reason for hiding this comment

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

個人的に二重ループになっていると少し複雑かなと思いました。if 文を使って leftright を順に進めていくようにするとループ自体は1つなのでわかりやすいかもです。またリーダブルコードという本には beginend は 開閉区間([begin, end))の場合に用いるというような記述があったので、誤解を生む可能性があるかもです。(ここは所属組織の文化や慣習が大きいと思いますが)

Suggested change
for end in range(len(cumsum)):
while cumsum[end] - cumsum[begin] >= target:
min_length = min(min_length, end - begin)
begin += 1
left = 0
right = 1
while right < len(cumsum):
if cumsum[right] - cumsum[left] < target:
right += 1
else:
min_size = min(min_size, right - left)
left += 1

Copy link

@hayashi-ay hayashi-ay left a comment

Choose a reason for hiding this comment

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

良いと思います。

@SuperHotDogCat
Copy link

良いと思います。

def minSubArrayLen(self, target: int, nums: List[int]) -> int:
cumsum = [0]
for num in nums:
cumsum.append(cumsum[-1] + num)

Choose a reason for hiding this comment

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

累積和を求めるときのこの書き方良いですね、参考にします。
自分が書くときのcumsum[i + 1] = nums[i] + cumsum[i]より見やすいと思いました。

cumsum.append(cumsum[-1] + num)
min_length = len(nums) + 1
for i in range(len(cumsum)):
j = bisect_left(cumsum, cumsum[i] + target)

Choose a reason for hiding this comment

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

i, j はもう少し変数名こだわっても良いかと思いました。
i を start_index (or start), jがend_index (or end)とかですかね?(ちょっと自信ないですが。)

assert target > 0
min_length = len(nums) + 1
subarray_sum = 0
left = -1 # exclusive

Choose a reason for hiding this comment

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

感想: indexに-1設定できると左の開区間を表現しやすくていいですね

(普段書いているRustだとこれがとってもやりにくい)

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.

7 participants