2021-03-31:配列arrが与えられ、値vが与えられました。平均値がv以下である最長のサブ配列の長さを見つけます。
フーダの答え2021-03-31:
この質問は、昨日の質問の変形です。配列の各要素からvを減算し、最長のサブ配列の長さ<= 0を見つけます。
1.プレフィックスと+順序付きリスト。時間計算量はO(N * lgN)です。コードはありません。
2.スライディングウィンドウ。時間計算量はO(N)です。この質問は自然の知恵では想像できず、敏感さが必要です。コードがあります。
配列の各要素からvを引きます。
minSum配列、最小の累積合計、iで始まる最小の値。
最小値であるiで始まるminSumEnd配列。ここで、は右の境界です。
スライディングウィンドウを使用すると、右のポインタは一度に複数の位置に移動し、左のポインタは一度に1つの位置に移動します。
2つのforループが使用されますが、右ポインターはフォールバックしないため、複雑さはO(N)です。
コードはgolangで書かれています。コードは次のように表示されます。
package main
import "fmt"
//https://github.com/algorithmzuo/algorithmbasic2020/blob/master/src/class40/Code04_AvgLessEqualValueLongestSubarray.java
func main() {
arr := []int{1000, -10, 60, -60, 3, 1, -2, 1, 10}
v := 5
ret := ways1(arr, v)
fmt.Println(ret)
}
func ways1(arr []int, v int) int {
arrLen := len(arr)
if arrLen == 0 {
return 0
}
//数组的所有值都减掉平均值
for i := 0; i < arrLen; i++ {
arr[i] -= v
}
//最小累加和数组
//最小累加和数组的右边界
minSums := make([]int, arrLen)
minSumEnds := make([]int, arrLen)
minSums[arrLen-1] = arr[arrLen-1]
minSumEnds[arrLen-1] = arrLen - 1
for i := arrLen - 2; i >= 0; i-- {
if minSums[i+1] < 0 {
minSums[i] = arr[i] + minSums[i+1]
minSumEnds[i] = minSumEnds[i+1]
} else {
minSums[i] = arr[i]
minSumEnds[i] = i
}
}
R := 0
sum := 0
ans := 0
for L := 0; L < arrLen; L++ {
//R循环右扩
for R < arrLen && sum+minSums[R] <= 0 {
sum += minSums[R]
R = minSumEnds[R] + 1
}
//统计答案
ans = getMax(ans, R-L)
//L右扩前,需要处理
if R > L {
sum -= arr[L]
} else {
R = L + 1
}
}
//数组修改了,需要还原
for i := 0; i < arrLen; i++ {
arr[i] += v
}
return ans
}
func getMax(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
実行結果は以下のとおりです。