-
Notifications
You must be signed in to change notification settings - Fork 0
209. Minimum Size Subarray Sum #46
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
base: main
Are you sure you want to change the base?
Conversation
| } | ||
| result := math.MaxInt | ||
| for left := range nums { | ||
| right, _ := slices.BinarySearch(prefixSums[left:], prefixSums[left]+target) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
前回の探索結果の right よりも右くらいまではいえますかね。あんまり速度には影響がないかもしれませんが。そうなると、right から右に走査するのも一つですね。(そうすると step 1 に近い物になるでしょう。)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
書いてみました。
BinarySearch で調べる区間を前回の探索結果よりも右にしたもの。積極的に書きたいコードではない。
func minSubArrayLen(target int, nums []int) int {
prefixSums := make([]int, len(nums)+1)
for i := range nums {
prefixSums[i+1] = prefixSums[i] + nums[i]
}
if prefixSums[len(prefixSums)-1] < target {
return 0
}
result := math.MaxInt
lastRight := 0
for left := range nums {
subarrayRight, _ := slices.BinarySearch(prefixSums[lastRight+1:], prefixSums[left]+target)
if lastRight+subarrayRight+1 == len(prefixSums) {
break
}
result = min(result, (lastRight+subarrayRight+1)-left)
}
return result
}right から右に走査する。二分探索の対象が prefixSums[0:right] と始点を固定できるのがありがたい。二分探索で見つけるべきは prefixSums[right] - target を挿入できる位置のすぐ左のインデックスなので、BisectRight を自作した。
func BisectRight(nums []int, target int) int {
left := 0
right := len(nums) - 1
for left < right {
middle := (left+right+1) / 2
if nums[middle] <= target {
left = middle
} else {
right = middle - 1
}
}
return left
}
func minSubArrayLen(target int, nums []int) int {
prefixSums := make([]int, len(nums)+1)
for i := range nums {
prefixSums[i+1] = prefixSums[i] + nums[i]
}
if prefixSums[len(prefixSums)-1] < target {
return 0
}
result := math.MaxInt
for right := 1; right < len(prefixSums); right++ {
if prefixSums[right] < target {
continue
}
left := BisectRight(prefixSums[:right], prefixSums[right]-target)
result = min(result, right-left)
}
return result
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
はい。前回の結果を覚えておくならば、Binary Search よりも線形で探したほうが速そうですね。
| - https://github.com/olsen-blue/Arai60/pull/50/files#diff-6d4eb2707ed57d8037bfa2e5985424b237a407741a7602ba92b31e090d1cb096R164-R165 | ||
| - `min_length` と `prefix_sum` の更新順が自分のとは逆 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここのコードの意図ですが、下記のようなイメージでした。
・まずprefix_sum >= targetが現状において保証されているので、真っ先にmin_lengthの更新をしてみる。
・もしかすると、まだまだ記録を更新できるかもなので、windowを小さくしてみる。つまりprefix_sumを削り、削ったのでleftを右に1個進める。
・ここまでを自分の仕事分として次の担当に引き継ぐ。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
はい、そちらの方が自然だと思い、見習わせていただきました!
| } | ||
| result := math.MaxInt | ||
| for left := range nums { | ||
| right, _ := slices.BinarySearch(prefixSums[left:], prefixSums[left]+target) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
私は、prefix_sums全体を探索対象にして、target_indexを求めてしまってましたが、スライスした方が時間計算量は少なく済んでより効率的になりそうですね。
https://github.com/olsen-blue/Arai60/pull/50/files#diff-6d4eb2707ed57d8037bfa2e5985424b237a407741a7602ba92b31e090d1cb096R189
また、スライスすることで、rightが(おそらく)相対インデックスになるので、result = min(result, right)に直接使えるのもいいですね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
後から見返したところ left は prefixSums 全体の中のインデックスで right はスライスされたものの中でのインデックスとなっており、対称性がないのがちょっと読み手にとってトラップかもしれません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
たしかに非対称なのが認知不可があるかもですね。
アイデアベースですが、leftをfrom_index、rightをlengthとかにしたらどうでしょう、みたいなことを思いました。subarray_lengthまで言っちゃっても良いかもですね。
| left := 0 | ||
| for right := range len(nums) { | ||
| subarraySum += nums[right] | ||
| if subarraySum < target { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この if 文は削除しても同じ結果になると思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
はい、ここは敢えて書くかどうか迷いましたが、目の動きを減らすために入れてみました。
https://leetcode.com/problems/minimum-size-subarray-sum/description/