Skip to content

Conversation

@hroc135
Copy link
Owner

@hroc135 hroc135 commented Apr 3, 2025

}
result := math.MaxInt
for left := range nums {
right, _ := slices.BinarySearch(prefixSums[left:], prefixSums[left]+target)
Copy link

Choose a reason for hiding this comment

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

前回の探索結果の right よりも右くらいまではいえますかね。あんまり速度には影響がないかもしれませんが。そうなると、right から右に走査するのも一つですね。(そうすると step 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.

書いてみました。
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
}

Copy link

Choose a reason for hiding this comment

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

はい。前回の結果を覚えておくならば、Binary Search よりも線形で探したほうが速そうですね。

Comment on lines +43 to +44
- https://github.com/olsen-blue/Arai60/pull/50/files#diff-6d4eb2707ed57d8037bfa2e5985424b237a407741a7602ba92b31e090d1cb096R164-R165
- `min_length` と `prefix_sum` の更新順が自分のとは逆
Copy link

@olsen-blue olsen-blue Apr 6, 2025

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個進める。
・ここまでを自分の仕事分として次の担当に引き継ぐ。

https://github.com/olsen-blue/Arai60/pull/50/files#diff-6d4eb2707ed57d8037bfa2e5985424b237a407741a7602ba92b31e090d1cb096R163-R166

Copy link
Owner Author

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)
Copy link

@olsen-blue olsen-blue Apr 6, 2025

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)に直接使えるのもいいですね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

後から見返したところ left は prefixSums 全体の中のインデックスで right はスライスされたものの中でのインデックスとなっており、対称性がないのがちょっと読み手にとってトラップかもしれません。

Choose a reason for hiding this comment

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

たしかに非対称なのが認知不可があるかもですね。
アイデアベースですが、leftfrom_indexrightlengthとかにしたらどうでしょう、みたいなことを思いました。subarray_lengthまで言っちゃっても良いかもですね。

left := 0
for right := range len(nums) {
subarraySum += nums[right]
if subarraySum < target {
Copy link

Choose a reason for hiding this comment

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

この if 文は削除しても同じ結果になると思います。

Copy link
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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants