目录
- 1.预测赢家
- [2. 组合总和 III](#2. 组合总和 III)
1.预测赢家
给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。
玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手。开始时,两个玩家的初始分值都是 0 。每一回合,玩家从数组的任意一端取一个数字(即,nums0 或 numsnums.length - 1),取到的数字将会从数组中移除(数组长度减 1 )。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时,游戏结束。
如果玩家 1 能成为赢家,返回 true 。如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true 。你可以假设每个玩家的玩法都会使他的分数最大化。
示例 1:
输入:nums = 1,5,2
输出:false
解释:一开始,玩家 1 可以从 1 和 2 中进行选择。
如果他选择 2(或者 1 ),那么玩家 2 可以从 1(或者 2 )和 5 中进行选择。如果玩家 2 选择了 5 ,那么玩家 1 则只剩下 1(或者 2 )可选。
所以,玩家 1 的最终分数为 1 + 2 = 3,而玩家 2 为 5 。
因此,玩家 1 永远不会成为赢家,返回 false 。
示例 2:
输入:nums = 1,5,233,7
输出:true
解释:玩家 1 一开始选择 1 。然后玩家 2 必须从 5 和 7 中进行选择。无论玩家 2 选择了哪个,玩家 1 都可以选择 233 。
最终,玩家 1(234 分)比玩家 2(12 分)获得更多的分数,所以返回 true,表示玩家 1 可以成为赢家。
思路
递归
每名玩家都想办法让自己赢,在尝试所有情况下后如果还是无法获胜,则表明自己必输,否则按照能获胜的方式去尝试。玩家一有主动权,只要有一种情况能获胜即可。
java
class Solution {
public boolean predictTheWinner(int[] nums) {
return firstHand(nums,0,nums.length-1,0,0);
}
//玩家一
//尽最大努力让自己赢
private boolean firstHand(int[] nums,int start,int end,int t1,int t2){
if(start>end){
return t1>=t2;
}
//两种可能,选左
t1+=nums[start];
if(!secondHand(nums,start+1,end,t1,t2)){
return true;
}
//选右
t1-=nums[start];
t1+=nums[end];
if(!secondHand(nums,start,end-1,t1,t2)){
return true;
}
return false;
}
//玩家二
private boolean secondHand(int[] nums,int start,int end,int t1,int t2){
if(start>end){
return t2>t1;
}
t2+=nums[start];
if(!firstHand(nums,start+1,end,t1,t2)){
return true;
}
t2-=nums[start];
t2+=nums[end];
if(!firstHand(nums,start,end-1,t1,t2)){
return true;
}
return false;
}
}
时间复杂度: O ( 2 n ) O(2^n) O(2n)
空间复杂度: O ( n ) O(n) O(n)
动态规划
使用二维数组dpnn,dpij表示取值范围为i,j范围内时,当前选手得分与另一个选手得分差值。
当i=j时,当前玩家只有一种选择,即numsi,此时dpii = numsi
当i<j时,当前玩家可以选择numsi或者numsj,以使得自己得分的最大化,即
dpij = max{numsi-dpi+1j,numsj+dpij-1}
最后判断dp0n-1是否大于等于0即可
java
class Solution {
public boolean predictTheWinner(int[] nums) {
int n = nums.length;
int[][] dp = new int[n][n];
for(int i=0;i<n;i++){
dp[i][i] = nums[i];
}
for(int i=n-1;i>=0;i--){
for(int j=i+1;j<n;j++){
dp[i][j] = Math.max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1]);
}
}
return dp[0][n-1]>=0;
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n 2 ) O(n^2) O(n2) 若优化动态规划空间的话,空间复杂度为 O ( n ) O(n) O(n)
2. 组合总和 III
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7
输出: \[1,2,4]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
示例 2:
输入: k = 3, n = 9
输出: \[1,2,6, 1,3,5, 2,3,4]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。
示例 3:
输入: k = 4, n = 1
输出: \[\]
解释: 不存在有效的组合。
在1,9范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。
思路
递归
java
class Solution {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
dfs(9,n,k);
return ans;
}
private void dfs(int n,int leftSum,int d){
if(leftSum<0||leftSum>(n*2-d+1)*d/2){
return ;
}
if(d==0&&leftSum==0){
ans.add(new ArrayList<>(path));
return ;
}
for(int j=n;j>0;j--){
path.add(j);
dfs(j-1,leftSum-j,d-1);
path.removeLast();
}
}
}