最大子数组和

Problem: 53. 最大子数组和

思路

双指针 但是用count保存双端的值 哪端count小哪端移动

解题方法

描述你的解题方法

复杂度

时间复杂度:

添加时间复杂度, 示例: $O(n)$

空间复杂度:

添加空间复杂度, 示例: $O(n)$

Code

// 这版性能一般
func maxSubArray(nums []int) int {
	resultArray := nums[:]
	leftIndex, rightIndex := 0, len(nums)-1
	// leftStart, rightStart := leftIndex, rightIndex
	leftCount, rightCount := nums[leftIndex], nums[rightIndex]

	for {
		// 当数组足够小直接退出,不用分
		if len(nums) == 1 {
			return nums[0]
		}

		// 判断下标距离, 如果下标相邻直接退出
		if leftIndex+1 == rightIndex {
			break
		}

		// 移动小的那端
		if leftCount < rightCount {
			leftIndex++
			if leftCount < 0 {
				resultArray = resultArray[leftIndex:]
				// 数组变化时leftIndex要缩小,leftIndex归为0
				rightIndex -= leftIndex
				leftIndex = 0
				leftCount = resultArray[leftIndex]
			} else {
				leftCount += resultArray[leftIndex]
			}
		} else {
			rightIndex--
			if rightCount < 0 {
				// 数组变化时rightIndex++
				resultArray = resultArray[:rightIndex+1]
				rightCount = resultArray[rightIndex]
			} else {
				rightCount += resultArray[rightIndex]
			}
		}

	}
	return max(leftCount+rightCount, max(leftCount, rightCount))
}

func max(a int, b int) int {
	if a > b {
		return a
	}
	return b
}

Code

// 将消耗比较大的切片去掉 性能已经不错了
func maxSubArray(nums []int) int {
	// 当数组足够小直接退出,不用分
	if len(nums) == 1 {
		return nums[0]
	}
	leftIndex, rightIndex := 0, len(nums)-1
	leftCount, rightCount := nums[leftIndex], nums[rightIndex]

	for {
		// 判断下标距离, 如果下标相邻直接退出
		if leftIndex+1 == rightIndex {
			break
		}
		// 移动小的那端
		if leftCount < rightCount {
			leftIndex++
			if leftCount < 0 {
				// 小于0舍弃掉并换成当前值
				leftCount = nums[leftIndex]
			} else {
				leftCount += nums[leftIndex]
			}
		} else {
			rightIndex--
			if rightCount < 0 {
				// 小于0舍弃掉并换成当前值
				rightCount = nums[rightIndex]
			} else {
				rightCount += nums[rightIndex]
			}
		}
	}
	return max(leftCount+rightCount, max(leftCount, rightCount))
}

func max(a int, b int) int {
	if a > b {
		return a
	}
	return b
}
// 优秀的递归 这个思路如果存储起来可以做到查询?
package main

func main() {

	temp := maxSubArray([]int{-2, 1, -3, 4, -1, 2, 1, -5, 4})
	println(temp)
	// for _, v := range temp {
	// 	println(v)
	// }
	// for i := 0; i < len(temp); i++ {
	// 	for j := 0; j < len(temp[i]); j++ {
	// 		print(temp[i][j], " ")
	// 	}
	// 	println()
	// }
}

// maxSubArray 接收一个整数切片nums,并返回其最大子数组和
func maxSubArray(nums []int) int {
	// 调用get函数构建线段树并查询整个数组的最大子数组和
	return get(nums, 0, len(nums)-1).mSum
}

// pushUp 用于合并两个子节点的状态,生成父节点的状态
func pushUp(l, r Status) Status {
	// iSum 是当前区间的元素和
	iSum := l.iSum + r.iSum
	// lSum 是当前区间以左端点为起点的最大子数组和
	lSum := max(l.lSum, l.iSum+r.lSum)
	// rSum 是当前区间以右端点为起点的最大子数组和
	rSum := max(r.rSum, r.iSum+l.rSum)
	// mSum 是当前区间的最大子数组和
	mSum := max(max(l.mSum, r.mSum), l.rSum+r.lSum)
	// 返回合并后的状态
	return Status{lSum, rSum, mSum, iSum}
}

// get 用于递归地构建线段树并返回指定区间的状态
func get(nums []int, l, r int) Status {
	// 如果区间只有一个元素,直接返回该元素的状态
	if l == r {
		return Status{nums[l], nums[l], nums[l], nums[l]}
	}
	// 计算中间位置
	m := (l + r) >> 1
	// 递归地构建左半部分线段树
	lSub := get(nums, l, m)
	// 递归地构建右半部分线段树
	rSub := get(nums, m+1, r)
	// 合并左右子树的状态,生成当前区间的状态
	return pushUp(lSub, rSub)
}

// max 函数返回两个整数中的较大值
func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

// Status 结构体用于存储线段树节点的状态
type Status struct {
	lSum, rSum, mSum, iSum int
}

// 字段解释:
// lSum: 当前区间以左端点为起点的最大子数组和
// rSum: 当前区间以右端点为起点的最大子数组和
// mSum: 当前区间的最大子数组和
// iSum: 当前区间的元素和
posted @ 2024-06-07 09:09  烟熏咸鱼干  阅读(2)  评论(0编辑  收藏  举报