这个周的每日一题,做算法,要有想象力,要足够充分发掘已知条件。
题目
https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards/
解法
回溯 + 双指针
这道题目每次都只能从开头或者末尾拿一个,那么做决策的过程可以是为一个二叉树。
我们分别用两个指针指向还未遍历的队头结尾,用作指向左子树和右子树的指针。
1 2 3 4 5 6 7 8 9 10 11 12 13
| const trackback = (cardPoints, k, count, left, right, result) => { if (count === k) { return result; } else { const leftresult = trackback(cardPoints, k, count + 1, left + 1, right, result + cardPoints[left]); const rightresult = trackback(cardPoints, k, count + 1, left, right - 1, result + cardPoints[right]); return Math.max(leftresult, rightresult); } }
var maxScore = function(cardPoints, k) { return trackback(cardPoints, k, 0, 0, cardPoints.length - 1, 0); };
|
反向思考+滑动窗口
上面这种解法是常规解法,但是其实这个题目还有个已知条件我们没有好好利用。
就是每次只能从头或者尾取值,那也就是说完成k个的取值后,剩下的是连续的。
那么假设数组长度为n,则取完k个值后剩n-k个连续数组。
我们只需要求出n-k的连续数组的最小值,就可以推出取值的最大值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var maxScore = function(cardPoints, k) { const n = cardPoints.length; const windowSize = n - k; let sum = 0; for (let i = 0; i < windowSize; ++i) { sum += cardPoints[i]; } let minSum = sum; for (let i = windowSize; i < n; ++i) { sum += cardPoints[i] - cardPoints[i - windowSize]; minSum = Math.min(minSum, sum); } let totalSum = 0; for (let i = 0; i < n; i++) { totalSum += cardPoints[i]; } return totalSum - minSum; };
|