1、問題描述
給定一個數組nums,a、b兩人輪流從數組的左端或右端取一個數作爲自己的得分,假設兩人足夠聰明,都採用最優的策略取數,且a先取,問a能能拿到的最大的分數是多少?
示例:
輸入:nums=[4,7,5,3]
輸出:10
解釋:a能拿到的最大分數爲7+3=10.
2、解題思路
分析:由題意,我們可以明確以下幾點:
(1) 當選手、在子數組中取數時,無論怎麼取,、最終的得分之和總是一個固定值,這個固定值等於子數組的所有元素之和;
(2) 假設表示選手在子數組取數時的最優解,由於選手每次也是選擇最優的解,所以或者就代表了選手在子數組取數時的最優解(因爲選手取了一個數後剩下的元素要麼是要麼是)。
(3) 考慮到和的得分之和固定,即的得分加上的得分等於固定值,若想讓選手的得分最高,則等價於讓的得分最低。
根據以上結論,我們採用動態規劃來解決該問題:
(1)定義狀態:
:選手在子數組上取數時的最大得分;
(2)狀態轉移:
選手在子數組的得分等於子數組之和減去選手子數組的得分,而選手要想得分最高,等價於選手的得分最低。
(3)確定起始:
當只剩下一個數時,取走它。
。
(4)確定終止
選手在整個數組取數時的最大得分。
注意,由於涉及到區間數組和的問題,因此可以採用前綴和來進行優化。
3、代碼實現
int maxScore(vector<int> nums){
int len = nums.size();
//求數組的前綴和數組
vector<int> sums(len,0);
for(int i = 0; i < len; i++){
if(i > 0){
sums[i] = sums[i-1] + nums[i]
}
else{
sums[i] = nums[i];
}
}
//動態規劃
vector<vector<int>> dp(len, vector<int>(len,0));
for(int i = 0; i < len; i++){
for(int j=i; j >=0; j--){
if(j == i){
dp[i][i] = nums[i];
}
else{
int scoresum = j > 0 ? sum[i] - sum[j-1] : sum[i];
dp[j][i] = scoresum - min(dp[j+1][i],dp[j][i-1];
}
}
}
return dp[0][len -1];
}