1423.可获得的最大点数

93 阅读2分钟

题目:
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。

每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。

你的点数就是你拿到手中的所有卡牌的点数之和。

给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。

算法:

**算法一:双指针 **

本质上是窗口长度为k,求窗口内的最大值。那我们初始时,设置长度为k的窗口[0,0]+[n-k,n-1],其中初始值left=0,right=n-k,left右移,right右移,求窗口内最大值即可

func maxScore(cardPoints []int, k int) int {
	left, right := 0, len(cardPoints) - 1
	ans := 0
	score := 0
	// 从右侧拿k张牌
	for i := 0; i < k; i ++ {
		score = score + cardPoints[right]
		right --
	}
	if k >= len(cardPoints) {
		return score
	}
	ans = score
	// 跳出上面的for循环时,[right, n - 1]有k + 1个数,所有right右移一位
	for right = right + 1; right < len(cardPoints); right ++ {
		score = score - cardPoints[right]
		score = score + cardPoints[left]
		left ++
		if score > ans {
			ans = score
		}
	}
	return ans
}

**方法二:滑动窗口 **

从头尾取出长度为k个连续的数,则中间还剩下n- k个,问题转换为cardPoints的和sum 与 cardPoints长度为n - k的滑动窗口的差的最大值

func maxScore(cardPoints []int, k int) int {
	n := len(cardPoints)
	sum, windowSum := 0, 0 
	for i := range cardPoints {
		sum = sum + cardPoints[i]
	}
	ans := 0 
        // 下面的for循环处理不了k == n的情况,k == n是continue不会生效,生效了ans也是0
	if k == n {
		return sum
	}
	// 求滑动窗口之和
	for left, right := 0, 0; right < len(cardPoints); right ++ {
		windowSum = windowSum + cardPoints[right]
		if right - left + 1 < n - k {
			continue
		}
		if sum - windowSum > ans {
			ans = sum - windowSum
		}
		windowSum = windowSum - cardPoints[left]
		left ++
	}
	return ans
}

**方法三:滑动窗口优化 **

对于方法二的求解过程,注意到我们要求滑动窗口长度为n - k的区间和的最小值,前缀和可以在O(1)时间得到结果,

func maxScore(cardPoints []int, k int) int {
	n := len(cardPoints)
        // 前缀和小技巧1,数组长度n + 1
	prefixSum := make([]int, n + 1)
	for i := range cardPoints {
		prefixSum[i + 1] = prefixSum[i] + cardPoints[i]
	}
	sum := prefixSum[n]
	minWindowSum := math.MaxInt64
	windowSize := n - k
	for i := 0; i + windowSize <= n; i ++ {
               // 前缀和小技巧2,prefixSum[i + windowSize] - prefixSum[i]求区间和[i + 1, i + windowSize]
		minWindowSum = min(minWindowSum, prefixSum[i + windowSize] - prefixSum[i])

	}
	return sum - minWindowSum
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}