2023-12-20:用go语言,给定一个数组arr,长度为n,在其中要选两个不相交的子数组。 两个子数组的累加和都要是T,返回所有满足情况中,两个子数组长度之和最小是多少? 如果没有有效方法,返回-
2023-12-20:用go語言,給定一個數(shù)組arr,長度為n,在其中要選兩個不相交的子數(shù)組。
兩個子數(shù)組的累加和都要是T,返回所有滿足情況中,兩個子數(shù)組長度之和最小是多少?
如果沒有有效方法,返回-1。
正式 :
2 <= n <= 10^6
0 <= arr[i] <= 10000
1 <= T <= 10^8
擴展 :
2 <= n <= 10^6
-10000 <= arr[i] <= 10000
1 <= T <= 10^8
都能時間復(fù)雜度做到O(N)。
來自字節(jié)。
答案2023-12-20:
來自左程云。
靈捷3.5
大體步驟如下:
Algorithm 1: minLenBothT1
1.初始化數(shù)組arr的累加和數(shù)組sum,并計算arr的累加和。
2.初始化變量ans為一個較大的整數(shù)。
3.使用四重循環(huán)遍歷所有可能的起始和結(jié)束索引組合(a, b, c, d)。
4.檢查子數(shù)組[a, b]和[c, d]的累加和是否等于目標值T。
5.如果滿足條件,則更新ans為兩個子數(shù)組長度之和的最小值。
6.如果ans的值沒有被更新過,則返回-1,否則返回ans。
Algorithm 2: minLenBothT2
1.初始化變量ans為一個較大的整數(shù)。
2.遍歷數(shù)組arr,尋找和為0的連續(xù)子數(shù)組,記錄其長度為cnt。
3.如果cnt大于等于2,則返回2作為結(jié)果。
4.對于每個起始索引l,從右側(cè)擴展子數(shù)組的結(jié)束索引r,使得子數(shù)組的和盡量接近目標值T。
5.記錄滿足和為T的子數(shù)組的最小長度到right[l]數(shù)組中。
6.從右到左遍歷數(shù)組arr,對于每個結(jié)束索引r,從左側(cè)縮小子數(shù)組的起始索引l,使得子數(shù)組的和盡量接近目標值T。
7.如果和為T且right[r+1]不是無窮大,則更新ans為當前長度+r-l+right[r+1]的最小值。
8.如果ans的值沒有被更新過,則返回-1,否則返回ans。
Algorithm 3: minLenBothT3
1.初始化變量ans為一個較大的整數(shù)。
2.構(gòu)建累加和出現(xiàn)次數(shù)的映射表sums,初始時將0的索引設(shè)置為-1。
3.構(gòu)建左側(cè)最小長度的數(shù)組left,初始時將所有元素設(shè)置為一個較大的整數(shù)。
4.遍歷數(shù)組arr,計算累加和sum,并檢查sum-t在sums中是否存在。
5.如果存在,則更新左側(cè)最小長度left[i]為當前索引i與sums[sum-t]之差。
6.更新sums[sum]為當前索引i。
7.從左到右遍歷left數(shù)組,將每個位置的值更新為其與前一個位置的較小值。
8.清空sums映射表,并將0的索引設(shè)置為數(shù)組arr的長度。
9.從右到左遍歷數(shù)組arr,計算累加和sum,并檢查sum-t在sums中是否存在且左側(cè)最小長度left[i-1]不是一個較大的整數(shù)。
10.如果滿足條件,則更新ans為當前長度+sums[sum-t]-i的最小值。
11.更新sums[sum]為當前索引i。
12.如果ans的值沒有被更新過,則返回-1,否則返回ans。
Algorithm 1:
-
時間復(fù)雜度:O(n^4)
-
空間復(fù)雜度:O(n)
Algorithm 2:
-
時間復(fù)雜度:O(n)
-
空間復(fù)雜度:O(n)
Algorithm 3:
-
時間復(fù)雜度:O(n)
-
空間復(fù)雜度:O(n)
go語言完整代碼如下:
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func minLenBothT1(arr []int, t int) int {
n := len(arr)
sum := make([]int, n)
sum[0] = arr[0]
for i := 1; i < n; i++ {
sum[i] = sum[i-1] + arr[i]
}
ans := math.MaxInt32
for a := 0; a < n-1; a++ {
for b := a; b < n-1; b++ {
for c := b + 1; c < n; c++ {
for d := c; d < n; d++ {
if sum1(a, b, sum) == t && sum1(c, d, sum) == t {
ans = min(ans, b+d-a-c+2)
}
}
}
}
}
if ans == math.MaxInt32 {
return -1
}
return ans
}
func sum1(l, r int, sum []int) int {
if l == 0 {
return sum[r]
}
return sum[r] - sum[l-1]
}
func minLenBothT2(arr []int, t int) int {
n := len(arr)
if t < 0 {
return -1
}
if t == 0 {
cnt := 0
for _, num := range arr {
if num == 0 {
cnt++
}
}
if cnt >= 2 {
return 2
}
return -1
}
right := make([]int, n)
for i := 0; i < n; i++ {
right[i] = math.MaxInt32
}
for l, r, sum := 1, 1, 0; l < n; l++ {
r = max(r, l)
for r < n && sum < t {
sum += arr[r]
r++
}
if sum == t {
right[l] = r - l
}
sum -= arr[l]
}
for i := n - 2; i >= 0; i-- {
right[i] = min(right[i], right[i+1])
}
ans := math.MaxInt32
for r, l, sum := n-2, n-2, 0; r >= 0; r-- {
l = min(l, r)
for l >= 0 && sum < t {
sum += arr[l]
l--
}
if sum == t && right[r+1] != math.MaxInt32 {
ans = min(ans, r-l+right[r+1])
}
sum -= arr[r]
}
if ans == math.MaxInt32 {
return -1
}
return ans
}
func minLenBothT3(arr []int, t int) int {
n := len(arr)
sums := make(map[int]int)
sums[0] = -1
left := make([]int, n)
for i := 0; i < n; i++ {
left[i] = math.MaxInt32
}
for i, sum := 0, 0; i < n-1; i++ {
sum += arr[i]
if l, found := sums[sum-t]; found {
left[i] = i - l
}
sums[sum] = i
}
for i := 1; i < n-1; i++ {
left[i] = min(left[i-1], left[i])
}
ans := math.MaxInt32
sums = make(map[int]int)
sums[0] = n
for i, sum := n-1, 0; i >= 1; i-- {
sum += arr[i]
if _, found := sums[sum-t]; found && left[i-1] != math.MaxInt32 {
ans = min(ans, left[i-1]+sums[sum-t]-i)
}
sums[sum] = i
}
if ans == math.MaxInt32 {
return -1
}
return ans
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func randomArray1(n, v int) []int {
arr := make([]int, n)
for i := 0; i < n; i++ {
arr[i] = rand.Intn(v + 1)
}
return arr
}
func randomArray2(n, v int) []int {
arr := make([]int, n)
for i := 0; i < n; i++ {
arr[i] = rand.Intn(2*v+1) - v
}
return arr
}
func main() {
rand.Seed(time.Now().UnixMicro())
N := 100
V := 100
T := 100
testTimes := 10000
fmt.Println("正式方法測試開始")
for i := 0; i < testTimes; i++ {
n := rand.Intn(N) + 2
v := rand.Intn(V) + 1
arr := randomArray1(n, v)
t := rand.Intn(T)
ans1 := minLenBothT1(arr, t)
ans2 := minLenBothT2(arr, t)
if ans1 != ans2 {
fmt.Println("出錯了!")
}
}
fmt.Println("正式方法測試結(jié)束")
fmt.Println("擴展方法測試開始")
for i := 0; i < testTimes; i++ {
n := rand.Intn(N) + 2
v := rand.Intn(V) + 1
arr := randomArray2(n, v)
t := rand.Intn(T)
ans1 := minLenBothT1(arr, t)
ans3 := minLenBothT3(arr, t)
if ans1 != ans3 {
fmt.Println("出錯了!")
}
}
fmt.Println("擴展方法測試結(jié)束")
}
總結(jié)
以上是生活随笔為你收集整理的2023-12-20:用go语言,给定一个数组arr,长度为n,在其中要选两个不相交的子数组。 两个子数组的累加和都要是T,返回所有满足情况中,两个子数组长度之和最小是多少? 如果没有有效方法,返回-的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【IT之家评测室】耕升 GeForce
- 下一篇: 怀念过去的句子简短 朋友圈发怀旧照片感言