改动态规划
交错字符串
解题思路:
基本上涉及到字符串匹配的问题都可以用动态规划。
本题我一开始想的是dp[i][j]: s1[0…i]与s2[0…j]的字串能否拼接成s3[0…i+j+1],但是初始化就出现了问题,dp[0][j]和dp[i][0]不好初始化,于是转变思路:
dp[i][j]: s1的前i个字符和s2的前j个字符能否交错拼接成s3[0…i+j-1],然后开辟dp数组 dp[s1.size()+1][s2.size()+1],则可初始化dp[0][0]=true.
class Solution {
public:
bool DP(string s1, string s2, string s3){
//dp[i][j]: s1的前i个字符与s2的前j个字符能否交错拼成s3的前i+j个字符
int n=s1.length();
int m=s2.length();
auto dp = vector < vector <int> > (n + 1, vector <int> (m + 1, false));
dp[0][0]=true;//""+""=""一定能拼成
for(int c=1;c<=m;++c){
dp[0][c]=s2.substr(0,c)==s3.substr(0,c);
}
for(int r=1;r<=n;++r){
dp[r][0]=s1.substr(0,r)==s3.substr(0,r);
}
for(int i=0;i<=n;++i){
for(int j=0;j<=m;++j){
int t=i+j-1;//拼成s3[0...i+j-1]
if(i>0&&s3[t]==s1[i-1]){
dp[i][j]|=dp[i-1][j];
}
if(j>0&&s3[t]==s2[j-1]){
dp[i][j]|=dp[i][j-1];
}
}
}
return dp[n][m];
}
bool isInterleave(string s1, string s2, string s3) {
if(s1==""&&s2==""){
return s3=="";
}
if(s1=="")return s3==s2;
if(s2=="")return s3==s1;
if(s3=="")return false;
//s1,s2,s3都不为空串
if(s1.length()+s2.length()!=s3.length())return false;
return DP(s1,s2,s3);
}
};
打家劫舍
class Solution {
public:
int DP(vector<int>& nums){
int n=nums.size();
vector<int>dp(n,0);
//dp[i]: 抢劫0~i最高金额
dp[0]=nums[0];
if(n==1)return dp[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<n;++i){
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
//dp[i-2]+nums[i]:偷i
//dp[i-1]:不偷i
}
return dp[n-1];
}
int rob(vector<int>& nums) {
return DP(nums);
}
};
等差数列划分
解题思路:
从左到右尝试,
class Solution {
public:
int DP(vector<int>& nums){
int res=0;
vector<int>dp(nums.size(),0);
for(int i=2;i<nums.size();++i){
if(nums[i]-nums[i-1]==nums[i-1]-nums[i-2]){
dp[i]=dp[i-1]+1;
}
res+=dp[i];
}
return res;
}
int numberOfArithmeticSlices(vector<int>& nums) {
return DP(nums);
}
};
解码方法
class Solution {
public:
int DP(string s){
vector<int>dp(s.length(),0);
if(s[0]=='0')return 0;
dp[0]=1;
if(s.length()==1)return 1;
stringstream ss;
ss<<s.substr(0,2);
int val;
ss>>val;
dp[1]=val<10?0:(val>26?(s[1]=='0'?0:1):(s[1]=='0'?1:2));
for(int i=2;i<s.length();++i){
dp[i]=s[i]=='0'?0:dp[i-1];
if(s[i-1]!='0'&&s.substr(i-1,2)<="26"){
dp[i]+=dp[i-2];
}
}
return dp[s.length()-1];
}
int numDecodings(string s) {
return DP(s);
}
};
背包问题
0-1 背包问题
分割等和子集
具体的解题思路参考:
class Solution {
public:
bool DP(int n,int target,vector<int>& nums){
//0-1背包问题,数字是物品,数值既是物品的重量,又是物品的价值
//dp[i][j]: 0~i选物品,背包的最大重量是j,最大价值
int dp[n][target+1];
for(int i=0;i<n;++i){
dp[i][0]=0;
}
int c=0;
for(;c<nums[0]&&c<=target;++c){
dp[0][c]=0;
}
for(;c<=target;++c){
dp[0][c]=nums[0];
}
for(int i=1;i<n;++i){
for(int j=1;j<=target;++j){
dp[i][j]=max((j-nums[i]>=0?dp[i-1][j-nums[i]]+nums[i]:0),dp[i-1][j]);
}
}
// for(int i=0;i<n;++i){
// for(int j=0;j<=target;++j){
// cout<<dp[i][j]<<" ";
// }
// cout<<endl;
// }
//返回 dp[n-1][target]==target
return dp[n-1][target]==target;
}
bool canPartition(vector<int>& nums) {
int sum=0;
for(int i:nums){
sum+=i;
}
if((sum&1)==1){
return false;
}
int target=sum>>1;
return DP(nums.size(),target,nums);
}
};
最后一块石头的重量 II
class Solution {
public:
int DP(vector<int>& stones,int target,int sum){
//dp[i][j]: 从0~i里面选石头,背包最大重量是j,可以获得的最大的价值
int n=stones.size();
int dp[n][target+1];
for(int i=0;i<n;++i){
dp[i][0]=0;
}
int c=0;
for(;c<stones[0]&&c<=target;++c){
dp[0][c]=0;
}
for(;c<=target;++c){
dp[0][c]=stones[0];
}
for(int i=1;i<n;++i){
for(int j=1;j<=target;++j){
dp[i][j]=max(dp[i-1][j],j-stones[i]>=0?dp[i-1][j-stones[i]]+stones[i]:0);
}
}
return (sum-dp[n-1][target])-dp[n-1][target];
}
int lastStoneWeightII(vector<int>& stones) {
//尽量把石头分成重量相等的两份
int sum=0;
for(int i:stones){
sum+=i;
}
int target=sum>>1;
return DP(stones,target,sum);
}
};
目标和
class Solution {
public:
int DP(int n,int target,vector<int>& nums){
//0-1背包
//dp[i][j]: 0~i里面选物品,背包容量是j,恰好装满背包的方法数
int dp[n][target+1];
dp[0][0]=nums[0]==0?2:1;
for(int i=1;i<n;++i){//背包容量是0,装满的方法数,如果有0的话
dp[i][0]=nums[i]==0?(dp[i-1][0]>>1):dp[i-1][0];
}
for(int j=1;j<=target;++j){
if(j==nums[0]){
dp[0][j]=1;
}else{
dp[0][j]=0;
}
}
for(int i=1;i<n;++i){
for(int j=0;j<=target;++j){
dp[i][j]=dp[i-1][j]+(j-nums[i]>=0?dp[i-1][j-nums[i]]:0);
}
}
// for(int i=0;i<n;++i){
// for(int j=0;j<=target;++j){
// cout<<dp[i][j]<<" ";
// }
// cout<<endl;
// }
return dp[n-1][target];
}
int findTargetSumWays(vector<int>& nums, int target) {
//假设正数的和为x ,负数绝对值的和为 sum-x, x-(sum-x)=target
//2x=sum+target
//x=(sum+target)>>1;
int sum=0;
//sum+target奇数返回0
for(int i:nums){
sum+=i;
}
if(((sum+target)&1)==1||sum+target<0)return 0;
int x=(sum+target)>>1;
return DP(nums.size(),x,nums);
}
};
一和零
class Solution {
public:
int DP(vector<string>& strs,int m,int n){
int dp[m+1][n+1];
for(int i=0;i<=m;++i){
for(int j=0;j<=n;++j){
dp[i][j]=0;
}
}
for(string str:strs){
int cnt0=0;
int cnt1=0;
for(char c:str){
if(c=='0')cnt0++;
else cnt1++;
}
for(int i=m;i>=cnt0;--i){
for(int j=n;j>=cnt1;--j){
dp[i][j]=max(dp[i-cnt0][j-cnt1]+1,dp[i][j]);
}
}
}
return dp[m][n];
}
int findMaxForm(vector<string>& strs, int m, int n) {
return DP(strs,m,n);
}
};
完全背包问题
整数拆分
class Solution {
public:
int DP(int n){
//完全背包问题
//背包是容量是n,物品体积就是拆分的数,乘积最大化就是价值最大化
//dp[i] :将容量为i的背包装满
vector<int>dp(n+1,0);
if(n==2)return 1;
dp[1]=1;
dp[2]=1;
for(int i=3;i<=n;++i){
//dp[i]最大价值
for(int j=i-1;j>=1;--j){
dp[i]=max(j*max(i-j,dp[i-j]),dp[i]);
}
}
return dp[n];
}
int integerBreak(int n) {
return DP(n);
}
};
单词拆分
class Solution {
public:
unordered_set<string>set;
bool DP(string s, vector<string>& words){
int n=s.length();
int m=words.size();
vector<bool>dp(n+1,false);
//dp[i]: s的前i个字符组成的字串能否由字典里的单词拼接成
dp[0]=true;//容量为0的背包总可以恰好装满
for(int i=1;i<=n;++i){//i是背包
for(int j=0;j<i;++j){
string w=s.substr(j,i-j);
if(set.find(w)!=set.end()&&dp[j]){//容量为j恰好装满&&剩下的空间刚好可以被一件物品装满
dp[i]=true;break;
}
}
}
return dp[n];
}
bool wordBreak(string s, vector<string>& wordDict) {
for(string s:wordDict){
set.insert(s);
}
return DP(s,wordDict);
}
};
零钱兑换 II
class Solution {
public:
int DP(vector<int>& coins,int amount){
int n=coins.size();
//dp[i][j]: 从0~i中选硬币,恰好凑成j
int dp[n][amount+1];
for(int i=0;i<n;++i){
for(int j=0;j<=amount;++j){
dp[i][j]=0;
}
}
for(int j=0;j<=amount;++j){
if(j%coins[0]==0){
dp[0][j]=1;
}else{
dp[0][j]=0;
}
}
for(int i=0;i<n;++i){
dp[i][0]=1;
}
for(int i=1;i<n;++i){
for(int j=1;j<=amount;++j){
dp[i][j]=dp[i-1][j];
if(j-coins[i]>=0){
dp[i][j]+=dp[i][j-coins[i]];
}
}
}
return dp[n-1][amount];
}
int change(int amount, vector<int>& coins) {
return DP(coins,amount);
}
};
零钱兑换
class Solution {
public:
int DP(vector<int>& coins, int amount){
vector<int>dp(amount+1,INT_MAX);
//第一列初始化0,凑成0所需硬币0个
dp[0]=0;
for(int i=0;i<coins.size();++i){
for(int j=0;j<=amount;++j){
if(j>=coins[i]&&dp[j-coins[i]]<INT_MAX){
dp[j]=min(dp[j],dp[j-coins[i]]+1);
}
}
}
return dp[amount]==INT_MAX?-1:dp[amount];
}
int coinChange(vector<int>& coins, int amount) {
return DP(coins,amount);
}
};
组合总和 Ⅳ
class Solution {
public:
int DP(vector<int>& nums, int target){
int n=nums.size();
vector<int>dp(target+1,0);
dp[0]=1;
for(int i=1;i<=target;++i){
for(int j:nums){
if(i>=j&&dp[i]<INT_MAX-dp[i-j]){
dp[i]+=dp[i-j];
}
}
}
return dp[target];
}
int combinationSum4(vector<int>& nums, int target) {
return DP(nums,target);
}
};
完全平方数
class Solution {
public:
int DP(int n){
int dp[n+1];
dp[0]=0;
dp[1]=1;
for(int i=2;i<=n;++i){
//先求<i的最大的的平方数k*k
int k=process(i);
//dp[i]=min{dp[i-1*1],dp[i-2*2],...dp[i-k*k]}+1
int min=INT_MAX;
for(int j=1;j<=k;++j){
min=std::min(min,dp[i-j*j]);
}
// cout<<min<<endl;
dp[i]=min+1;
}
return dp[n];
}
int process(int n){
int left=1;
int right=sqrt(n);
int mid;
while(left<right){
mid=left+((right-left)>>1);
if(mid*mid==n){
return mid-1;
}
else if(mid*mid<n){
left=mid+1;
}else{
right=mid-1;
}
}
return left;
}
int numSquares(int n) {
return DP(n);
}
};
不同的二叉搜索树
class Solution {
public:
int DP(int n){
int dp[n+1];
if(n==1)return 1;
if(n==2)return 2;
dp[0]=1;
dp[1]=1;
dp[2]=2;
//dp[i]:有i个节点可以构造的二叉搜索树的个数
for(int i=3;i<=n;++i){
dp[i]=0;
for(int j=0;j<i;++j){//左树有j个节点,右树有(i-j-1)个节点
dp[i]+=dp[j]*dp[i-j-1];
//dp[i]= 左树有j个节点可以构造的二叉搜索树的个数*右树有(i-j-1)个节点可以构造的二//叉搜索树的个数
}
}
return dp[n];
}
int numTrees(int n) {
return DP(n);
}
};
跳跃游戏 II
class Solution {
public:
int DP(vector<int>& nums){
int dp[nums.size()];
dp[0]=nums[0];
for(int i=1;i<nums.size();++i){
dp[i]=max(dp[i-1]-1,nums[i]);
}
int loc=0;
int ans=0;
while(loc<nums.size()-1){
ans++;
loc+=dp[loc];
}
return ans;
//2 3 2 1 4
}
int jump(vector<int>& nums) {
if(nums.size()==1)return 0;
return DP(nums);
}
};
跳跃游戏
class Solution {
public:
bool DP(vector<int>& nums){
int dp[nums.size()];
dp[0]=nums[0];
for(int i=1;i<nums.size();++i){
if(dp[i-1]==0)return false;
dp[i]=max(nums[i],dp[i-1]-1);
}
return true;
}
bool canJump(vector<int>& nums) {
return DP(nums);
}
};
分割等和子集
解题思路:
dp[i] : 是否有子集和等于 i
转移方程: dp[i] |= dp[ i-nums[j] ]
class Solution {
public:
int All;
bool DP(vector<int>& nums){
bool dp[(All>>1)+1];
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=0;i<nums.size();++i){
for(int j=(All>>1);j>=nums[i];--j){
dp[j]|=dp[j-nums[i]];
}
}
return dp[All>>1];
}
bool canPartition(vector<int>& nums) {
if(nums.size()==1)return false;
int all=0;
for(int i:nums){
all+=i;
}
if((all&1)==1)return false;
All=all;
// return process(nums,0,0);
return DP(nums)>0?true:false;
}
};
按摩师
class Solution {
public int process(int[] nums,int index,int sum){//默认当前位置是可以选的
if(index==nums.length){
return sum;
}
if(index==nums.length-1){
return sum+nums[index];
}
return Math.max(process(nums,index+1,sum),process(nums,index+2,sum+nums[index]));
}
public int DP(int[] nums) {
//index: 0~nums.length
if(nums==null||nums.length==0)return 0;
int[] dp=new int[nums.length+1];
dp[nums.length-1]=nums[nums.length-1];
for(int i=nums.length-2;i>=0;--i) {
dp[i]=Math.max(dp[i+1], dp[i+2]+nums[i]);
}
return Math.max(dp[0], dp[1]);
}
public int massage(int[] nums) {
return DP(nums);
}
}
除数博弈
class Solution {
//who: 0:爱丽丝 1:鲍勃
public boolean process(int n,int who){
if(n==1){
if(who==0){
return false;
}else{
return true;
}
}
//n>=2
boolean ans=false;
if(who==0){//轮到爱丽丝
for(int i=(int)Math.sqrt(n);i>=1;--i){
if(n%i==0){
ans=process(n-i,1);
}
}
}//轮到鲍勃
else{
for(int i=(int)Math.sqrt(n);i>=1;--i){
if(n%i==0){
ans=process(n-i,0);
}
}
}
return ans;
}
public boolean DP(int n) {
//n: 1~n
boolean[] dp0=new boolean[n+1];
boolean[] dp1=new boolean[n+1];
dp0[1]=false;
dp1[1]=true;
for(int i=2;i<=n;++i) {
for(int j=(int)Math.sqrt(i);j>=1;--j) {
if(i%j==0) {
dp0[i]=dp1[i-j];
dp1[i]=dp0[i-j];
}
}
}
return dp0[n];
}
public boolean divisorGame(int n) {
return DP(n);
}
}
使用最小花费爬楼梯
class Solution {
public int process(int[] cost,int index,int sum){
if(index>=cost.length){//已经没有台阶了,花费为0
return sum;
}
if(index==cost.length-1){//最后的台阶
return sum+cost[index];
}
//还没有到最后一个台阶
int ans=0;
ans=sum+process(cost,index+1,sum+cost[index]);
ans=Math.min(ans,sum+process(cost,index+2,sum+cost[index]));
return ans;
}
public int DP(int[] cost) {
//index: 0~cost.length
int[] dp=new int[cost.length+1];
dp[cost.length-1]=cost[cost.length-1];
for(int i=cost.length-2;i>=0;--i) {
dp[i]=Math.min(dp[i+1], dp[i+2])+cost[i];
}
return Math.min(dp[0],dp[1]);
}
public int minCostClimbingStairs(int[] cost) {
return DP(cost);
}
}
比特位计数
题解:
对于一个二进制数来说,如果它的 最低位为1 (%2 为 1),则它与 n/2 的 1 个数相差1。 如果它的 最低位为 0,则它与 n/2 的 1 个数相同
class Solution {
public int[] DP(int n){
int[] dp=new int[n+1];
if(n==0)return dp;
dp[1]=1;
for(int i=2;i<=n;++i){
//i是偶数
if((i&1)==0){
dp[i]=dp[i>>1];
}
//i是奇数
else{
dp[i]=dp[i>>1]+1;
}
}
return dp;
}
public int[] countBits(int n) {
return DP(n);
}
}
爬楼梯
class Solution {
//暴力尝试
public int process(int rest){
if(rest<0){
return 0;
}
if(rest==0||rest==1){
return 1;
}
//rest>0
return process(rest-1)+process(rest-2);
}
//动态规划
public int DP(int n) {
//rest: 0~n
int[] dp=new int[n+1];
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;++i) {
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
public int climbStairs(int n) {
return DP(n);
}
}
机器人到达指定位置方法数
import java.util.Scanner;
public class Robot {
public static int ways(int N,int P,int cur,int rest) {
if(rest==0) {
return cur==P?1:0;
}
if(cur==1)return ways(N,P,cur+1,rest-1);
if(cur==N)return ways(N,P,cur-1,rest-1);
return ways(N,P,cur-1,rest-1)+ways(N,P,cur+1,rest-1);
}
public static int getAns(int N,int P,int M,int K) {
if(M<1||M>N)return 0;
return ways(N,P,M,K);
}
public static int waysDP(int N,int P,int M,int K) {
//cur: 1~N rest: 0~K
int[][] dp=new int[N+1][K+1];
dp[P][0]=1;
for(int col=1;col<=K;++col) {
dp[1][col]=dp[2][col-1];
for(int row=2;row<N;++row) {
dp[row][col]=(dp[row-1][col-1]+dp[row+1][col-1])%(1000000007);
}
dp[N][col]=dp[N-1][col-1];
}
return dp[M][K]%(1000000007);
}
public static int Ans(int N,int P,int M,int K) {
if(M<1||M>N)return 0;
return waysDP(N,P,M,K);
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int N,M,K,P;
N=scan.nextInt();
M=scan.nextInt();
K=scan.nextInt();
P=scan.nextInt();
// System.out.println(getAns(N,P,M,K));
System.out.println(Ans(N,P,M,K));
}
}
排成一条线的纸牌博弈问题
import java.util.Scanner;
public class Main {
public static int win(int[] arr,int L,int R) {
return Math.max(f(arr,L,R),s(arr,L,R));
}
public static int f(int[] arr,int L,int R) {
if(L==R)return arr[L];
return Math.max(arr[L]+s(arr,L+1,R), arr[R]+s(arr,L,R-1));
}
public static int s(int[] arr,int L,int R) {
if(L==R)return 0;
return Math.min(f(arr,L+1,R),f(arr,L,R-1));
}
public static int winDP(int[] arr,int L,int R) {
//L: 0~arr.length-1 R: 0~arr.length-1
int[][] f=new int[arr.length][arr.length];
int[][] s=new int[arr.length][arr.length];
for(int i=0;i<arr.length;++i) {
f[i][i]=arr[i];
}
for(int col=1;col<arr.length;++col) {
int row=0,j=col;
while(row<arr.length&&j<arr.length) {
f[row][j]=Math.max(arr[row]+s[row+1][j],arr[j]+s[row][j-1]);
s[row][j]=Math.min(f[row+1][j], f[row][j-1]);
row++;
j++;
}
}
return Math.max(f[L][R],s[L][R]);
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[] arr=new int[n];
for(int i=0;i<n;++i) {
arr[i]=scan.nextInt();
}
// System.out.println(win(arr,0,n-1));
System.out.println(winDP(arr,0,n-1));
}
}
象棋中马的跳法
import java.util.Scanner;
public class Main {
public static int ways(int x,int y,int curx,int cury,int rest) {
//x:0~8 y:0~9 rest:0~k
if(rest==0) {
if(curx==x&&cury==y)return 1;
else return 0;
}
int ans=0;
if(curx-1>=0&&curx-1<9&&cury+2>=0&&cury+2<10) {
ans+=ways(x,y,curx-1,cury+2,rest-1);
}
if(curx+1>=0&&curx+1<9&&cury+2>=0&&cury+2<10) {
ans+=ways(x,y,curx+1,cury+2,rest-1);
}
if(curx-2>=0&&curx-2<9&&cury+1>=0&&cury+1<10) {
ans+=ways(x,y,curx-2,cury+1,rest-1);
}
if(curx+2>=0&&curx+2<9&&cury+1>=0&&cury+1<10) {
ans+=ways(x,y,curx+2,cury+1,rest-1);
}
if(curx-2>=0&&curx-2<9&&cury-1>=0&&cury-1<10) {
ans+=ways(x,y,curx-2,cury-1,rest-1);
}
if(curx+2>=0&&curx+2<9&&cury-1>=0&&cury-1<10) {
ans+=ways(x,y,curx+2,cury-1,rest-1);
}
if(curx-1>=0&&curx-1<9&&cury-2>=0&&cury-2<10) {
ans+=ways(x,y,curx-1,cury-2,rest-1);
}
if(curx+1>=0&&curx+1<9&&cury-2>=0&&cury-2<10) {
ans+=ways(x,y,curx+1,cury-2,rest-1);
}
return ans;
}
public static int waysDP(int x,int y,int k) {
int[][][] dp=new int[10][9][k+1];
dp[x][y][0]=1;
for(int l=1;l<=k;++l) {
for(int row=0;row<10;++row) {
for(int col=0;col<9;++col) {
if(row-2>=0&&row-2<10&&col-1>=0&&col-1<9) {
dp[row][col][l]+=dp[row-2][col-1][l-1];
}
if(row-2>=0&&row-2<10&&col+1>=0&&col+1<9) {
dp[row][col][l]+=dp[row-2][col+1][l-1];
}
if(row-1>=0&&row-1<10&&col-2>=0&&col-2<9) {
dp[row][col][l]+=dp[row-1][col-2][l-1];
}
if(row-1>=0&&row-1<10&&col+2>=0&&col+2<9) {
dp[row][col][l]+=dp[row-1][col+2][l-1];
}
if(row+1>=0&&row+1<10&&col-2>=0&&col-2<9) {
dp[row][col][l]+=dp[row+1][col-2][l-1];
}
if(row+1>=0&&row+1<10&&col+2>=0&&col+2<9) {
dp[row][col][l]+=dp[row+1][col+2][l-1];
}
if(row+2>=0&&row+2<10&&col-1>=0&&col-1<9) {
dp[row][col][l]+=dp[row+2][col-1][l-1];
}
if(row+2>=0&&row+2<10&&col+1>=0&&col+1<9) {
dp[row][col][l]+=dp[row+2][col+1][l-1];
}
}
}
}
return dp[0][0][k];
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int x,y,k;
x=scan.nextInt();
y=scan.nextInt();
k=scan.nextInt();
//System.out.println(ways(x,y,0,0,k));
System.out.println(waysDP(x,y,k));
}
}
Bob的生存概率
import java.util.Scanner;
public class Main {
public static int process(int N,int M,int row,int col,int rest) {
if(row<0||row>=N||col<0||col>=M)return 0;
if(rest==0) {
if(row>=0&&row<N&&col>=0&&col<M)return 1;
else return 0;
}
int ans=0;
if(row-1>=0)ans+=process(N,M,row-1,col,rest-1);
if(row+1<N)ans+=process(N,M,row+1,col,rest-1);
if(col-1>=0)ans+=process(N,M,row,col-1,rest-1);
if(col+1<M)ans+=process(N,M,row,col+1,rest-1);
return ans;
}
public static long DP(int N,int M,int i,int j,int k) {
//row: 0~N-1 col: 0~M-1 rest: 0~k
long[][][] dp=new long[N][M][k+1];
for(int row=0;row<N;++row) {
for(int col=0;col<M;++col) {
dp[row][col][0]=1;
}
}
for(int l=1;l<=k;++l) {
for(int row=0;row<N;++row) {
for(int col=0;col<M;++col) {
if(row-1>=0)dp[row][col][l]+=dp[row-1][col][l-1];
if(row+1<N)dp[row][col][l]+=dp[row+1][col][l-1];
if(col-1>=0)dp[row][col][l]+=dp[row][col-1][l-1];
if(col+1<M)dp[row][col][l]+=dp[row][col+1][l-1];
}
}
}
return dp[i][j][k];
}
public static long pow(int a,int b) {
long res=1;
for(int i=1;i<=b;++i) {
res*=a;
}
return res;
}
public static long gcd(long m,long n) {
return n==0?m:gcd(n,m%n);
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int N,M,i,j,k;
N=scan.nextInt();
M=scan.nextInt();
i=scan.nextInt();
j=scan.nextInt();
k=scan.nextInt();
//int ans1=process(N,M,i,j,k);
long all=pow(4,k);
//long g1=gcd(ans1,all);
//System.out.println(ans1/g1+"/"+all/g1);
long ans2=DP(N,M,i,j,k);
long g2=gcd(ans2,all);
System.out.println(ans2/g2+"/"+all/g2);
}
}
硬币数
class Solution {
public int ways(int[] arr,int index,int rest){
if(index==arr.length){
return rest==0?1:0;
}
int ans=0;
for(int i=0;i*arr[index]<=rest;++i){
ans+=ways(arr,index+1,rest-i*arr[index])%1000000007;
}
return ans%1000000007;
}
public int waysDP(int[] arr,int n){
//index: 0~arr.length rest: 0~n
int[][] dp=new int[arr.length+1][n+1];
dp[arr.length][0]=1;
for(int row=arr.length-1;row>=0;--row){
for(int col=0;col<=n;++col){
dp[row][col]=dp[row+1][col];
if(col-arr[row]>=0){
dp[row][col]+=dp[row][col-arr[row]]%1000000007;
}
}
}
return dp[0][n]%1000000007;
}
public int waysToChange(int n) {
int[] arr=new int[]{25,10,5,1};
return waysDP(arr,n);
}
}
子数组的最大累加和
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int N=scan.nextInt();
int[] arr=new int[N];
scan.nextLine();
String[] num=scan.nextLine().split(" ");
for(int i=0;i<N;++i) {
arr[i]=Integer.parseInt(num[i]);
}
int cur=0;
int max=Integer.MIN_VALUE;
for(int i=0;i<N;++i) {
cur+=arr[i];
max=Math.max(max, cur);
if(cur<0) {
cur=0;
}
}
System.out.println(max);
}
}
子矩阵的最大累加和
import java.util.Scanner;
public class Main {
public static int getSumMax(int[] arr) {
int cur=0;
int max=Integer.MIN_VALUE;
for(int i=0;i<arr.length;++i) {
cur+=arr[i];
max=Math.max(max, cur);
if(cur<0) {
cur=0;
}
}
return max;
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int row=scan.nextInt();
int col=scan.nextInt();
int[][] arr=new int[row][col];
for(int i=0;i<row;++i) {
for(int j=0;j<col;++j) {
arr[i][j]=scan.nextInt();
}
}
int ans=Integer.MIN_VALUE;
for(int i=0;i<row;++i) {
for(int j=i;j<row;++j) {
int[] sum=new int[col];
for(int c=0;c<col;++c) {
for(int k=i;k<=j;++k) {
sum[c]+=arr[k][c];
}
}
ans=Math.max(ans, getSumMax(sum));
}
}
System.out.println(ans);
}
}
最小路径和
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int m=scan.nextInt();
int[][] arr=new int[n][m];
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
arr[i][j]=scan.nextInt();
}
}
int[][] dp=new int[n][m];
dp[0][0]=arr[0][0];
for(int col=1;col<m;++col) {
dp[0][col]=dp[0][col-1]+arr[0][col];
}
for(int row=1;row<n;++row) {
dp[row][0]=dp[row-1][0]+arr[row][0];
}
for(int row=1;row<n;++row) {
for(int col=1;col<m;++col) {
dp[row][col]=Math.min(dp[row][col-1], dp[row-1][col])+arr[row][col];
}
}
System.out.println(dp[n-1][m-1]);
}
}
最长公共子序列
import java.util.*;
public class Solution {
/**
* longest common subsequence
* @param s1 string字符串 the string
* @param s2 string字符串 the string
* @return string字符串
*/
public String LCS (String s1, String s2) {
// write code here
if(s1==null||s2==null||s1.length()==0||s2.length()==0)return String.valueOf(-1);
int[][] dp=new int[s1.length()][s2.length()];
int col;
for(col=0;col<s2.length();++col) {
if(s1.charAt(0)==s2.charAt(col)) {
break;
}
}
for(int i=col;i<s2.length();++i) {
dp[0][i]=1;
}
int row;
for(row=0;row<s1.length();++row) {
if(s1.charAt(row)==s2.charAt(0)) {
break;
}
}
for(int i=row;i<s1.length();++i) {
dp[i][0]=1;
}
for(row=1;row<s1.length();++row) {
for(col=1;col<s2.length();++col) {
dp[row][col]=Math.max(dp[row-1][col], Math.max(dp[row][col-1], dp[row-1][col-1]));
if(s1.charAt(row)==s2.charAt(col)) {
dp[row][col]=Math.max(dp[row][col],1+dp[row-1][col-1]);
}
}
}
if(dp[s1.length()-1][s2.length()-1]==0)return String.valueOf(-1);
row=s1.length()-1;
col=s2.length()-1;
int len=dp[s1.length()-1][s2.length()-1];
char[] chs=new char[len];
int cur=len-1;
while(row>=1&&col>=1) {
if(s1.charAt(row)==s2.charAt(col)) {
if(cur<0)break;
chs[cur]=s1.charAt(row);
// System.out.print(chs[cur]+" ");
cur--;
row--;col--;
}else {
if(dp[row][col-1]>dp[row-1][col]) {
col--;
}else {
row--;
}
}
}
if(dp[row][col]==1) {
if(row==0) {
chs[cur]=s1.charAt(row);
}else {
chs[cur]=s2.charAt(col);
}
}
return String.valueOf(chs);
}
}
最长公共子串
空间复杂度 O ( n ∗ m ) O(n*m) O(n∗m)
import java.util.Scanner;
public class Main {
public static String process(String s1,String s2) {
if(s1==null||s2==null||s1.length()==0||s2.length()==0)return String.valueOf(-1);
int[][] dp=new int[s1.length()][s2.length()];
int end=0;
int len=0;
for(int col=0;col<s2.length();++col) {
if(s2.charAt(col)==s1.charAt(0)) {
dp[0][col]=1;
len=1;
}
}
for(int row=0;row<s1.length();++row) {
if(s1.charAt(row)==s2.charAt(0)) {
dp[row][0]=1;
end=row;
}
}
for(int row=1;row<s1.length();++row) {
for(int col=1;col<s2.length();++col) {
if(s1.charAt(row)==s2.charAt(col)) {
dp[row][col]=1+dp[row-1][col-1];
if(len<=1+dp[row-1][col-1]) {
len=1+dp[row-1][col-1];
end=row;
// System.out.println(end);
}
}
}
}
if(len==0)return String.valueOf(-1);
return s1.substring(end-len+1,end+1);
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s1=scan.nextLine();
String s2=scan.nextLine();
System.out.println(process(s1,s2));
}
}
空间复杂度 O ( 1 ) O(1) O(1)
import java.util.Scanner;
public class Main{
public static String process(String s1,String s2) {
if(s1==null||s2==null||s1.length()==0||s2.length()==0)return String.valueOf(-1);
int end=0;
int len=0;
int dp=0;
int i,j,t;
for(int col=s2.length()-1;col>=0;--col) {
i=0;
j=col;
t=0;
while(i<s1.length()&&j<s2.length()) {
if(s1.charAt(i)==s2.charAt(j)) {
t++;
if(t>len) {
len=t;
end=i;
}
}else {
t=0;
}
i++;
j++;
}
}
for(int row=1;row<s1.length();++row) {
j=0;
i=row;
t=0;
while(i<s1.length()&&j<s2.length()) {
if(s1.charAt(i)==s2.charAt(j)) {
t++;
if(t>len) {
len=t;
end=i;
}
}else {
t=0;
}
i++;
j++;
}
}
if(len==0)return String.valueOf(-1);
return s1.substring(end-len+1,end+1);
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s1=scan.nextLine();
String s2=scan.nextLine();
System.out.println(process(s1,s2));
}
}
最长递增子序列
import java.util.*;
public class AscentSequence {
public int process(int[] arr,int a,int b,int x){//二分
int left=a;
int right=b;
int mid=left+((right-left)>>2);
if(x>arr[b])return -1;
while(left<=right){
if(arr[mid]>=x){
right=mid-1;
}else{
left=mid+1;
}
mid=left+((right-left)>>2);
}
return left;
}
public int findLongest(int[] A, int n) {
// write code here
int[] ends=new int[n];
int[] dp=new int[n];
int max=0;
dp[0]=1;
ends[0]=A[0];
int cur=0;
max=Math.max(max,dp[0]);
for(int i=1;i<n;++i){
int index=process(ends,0,cur,A[i]);
if(index==-1){
ends[++cur]=A[i];
dp[i]=cur+1;
max=Math.max(max,dp[i]);
}else{
ends[index]=A[i];
dp[i]=index+1;
max=Math.max(max,dp[i]);
}
}
return max;
}
}
class Solution {
public:
int DP(vector<int>& nums){
int n=nums.size();
vector<int>dp(n,0);
//dp[i]:以nums[i]结尾的最长递增子序列
dp[0]=1;
int res=1;
if(n==1)return dp[0];
for(int i=1;i<n;++i){
dp[i]=1;
for(int j=0;j<i;++j){
if(nums[i]>nums[j]){
dp[i]=max(dp[i],dp[j]+1);
}
}
res=max(res,dp[i]);
}
return res;
}
int lengthOfLIS(vector<int>& nums) {
return DP(nums);
}
};
输出最长递增子序列
import java.util.Scanner;
public class Main {
public static int process(int[] arr,int a,int b,int x){//二分
int left=a;
int right=b;
int mid=left+((right-left)>>2);
if(x>arr[b])return -1;
while(left<=right){
if(arr[mid]>=x){
right=mid-1;
}else{
left=mid+1;
}
mid=left+((right-left)>>2);
}
return left;
}
public static void findLongest(int[] A, int n) {
// write code here
int[] ends=new int[n];
int[] dp=new int[n];
int max=0;
dp[0]=1;
ends[0]=A[0];
int cur=0;
max=Math.max(max,dp[0]);
int end=0;
for(int i=1;i<n;++i){
int index=process(ends,0,cur,A[i]);
if(index==-1){
ends[++cur]=A[i];
dp[i]=cur+1;
max=Math.max(max,dp[i]);
if(max==dp[i]) {
end=i;
}
}else{
ends[index]=A[i];
dp[i]=index+1;
max=Math.max(max,dp[i]);
if(max==dp[i]) {
end=i;
}
}
}
int[] ans=new int[max];
cur=max-1;
ans[cur--]=A[end];
for(int i=end-1;i>=0;--i) {
if(A[i]<ans[cur+1]&&dp[i]==cur+1) {
ans[cur--]=A[i];
}
}
for(int i=0;i<max;++i) {
System.out.print(ans[i]+" ");
}
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int[] arr=new int[n];
scan.nextLine();
String[] str=scan.nextLine().split(" ");
for(int i=0;i<n;++i) {
arr[i]=Integer.parseInt(str[i]);
}
findLongest(arr,n);
}
}
信封问题
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main{
public static int process(int[] arr,int a,int b,int x){//二分
int left=a;
int right=b;
int mid=left+((right-left)>>2);
if(x>arr[b])return -1;
while(left<=right){
if(arr[mid]>=x){
right=mid-1;
}else{
left=mid+1;
}
mid=left+((right-left)>>2);
}
return left;
}
public static int findLongest(int[] A, int n) {
int[] ends=new int[n];
int[] dp=new int[n];
int max=0;
dp[0]=1;
ends[0]=A[0];
int cur=0;
max=Math.max(max,dp[0]);
int end=0;
for(int i=1;i<n;++i){
int index=process(ends,0,cur,A[i]);
if(index==-1){
ends[++cur]=A[i];
dp[i]=cur+1;
max=Math.max(max,dp[i]);
if(max==dp[i]) {
end=i;
}
}else{
ends[index]=A[i];
dp[i]=index+1;
max=Math.max(max,dp[i]);
if(max==dp[i]) {
end=i;
}
}
}
return max;
}
public static class Envelope{
public int l;
public int w;
public Envelope(int a,int b) {
l=a;
w=b;
}
}
public static class Compare implements Comparator<Envelope>{
public int compare(Envelope o1,Envelope o2) {
if(o1.l!=o2.l) {
return o1.l-o2.l;
}else {
return o2.w-o1.w;
}
}
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
Envelope[] arr=new Envelope[n];
// scan.nextLine();
for(int i=0;i<n;++i) {
arr[i]=new Envelope(scan.nextInt(),scan.nextInt());
}
Arrays.sort(arr,new Compare());
int[] res=new int[n];
for(int i=0;i<n;++i) {
res[i]=arr[i].w;
}
System.out.println(findLongest(res,n));
}
}
数字转换字符串
import java.util.Scanner;
public class Main {
public static int process(String s,int index) {
if(index==s.length())return 1;
if(s.charAt(index)=='0')return 0;
int ans=process(s,index+1);
if(index==s.length()-1)return ans;
int num=(s.charAt(index)-'0')*10+(s.charAt(index+1)-'0');
if(num<27&&index+2<=s.length()) {
return ans+process(s,index+2);
}
return ans;
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s=scan.nextLine();
int ans=process(s,0);
System.out.println(ans);
}
}
import java.util.Scanner;
public class Main{
public static int dpways(String s) {
//index:0~s.length()
if(s==null||s.length()==0)return 0;
int[] dp=new int[s.length()+1];
dp[s.length()]=1;
dp[s.length()-1]=(s.charAt(s.length()-1)=='0'?0:1);
for(int i=s.length()-2;i>=0;--i) {
if(s.charAt(i)=='0')dp[i]=0;
else {
dp[i]=dp[i+1];
int num=(s.charAt(i)-'0')*10+(s.charAt(i+1)-'0');
if(num<27) {
dp[i]+=dp[i+2];
}
}
}
return dp[0];
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s=scan.nextLine();
// int ans=process(s,0);
System.out.println(dpways(s));
}
}
牛牛的背包问题
这道题 改进的暴力递归 可以通过,但是动态规划会异常,因为开辟的空间太大了,又不能空间压缩。
import java.util.Scanner;
public class Main{
public static int process(int[] arr,int index,int rest) {
if(rest<0) {
return 0;
}
if(index==arr.length) {
return 1;
}
int ans=process(arr,index+1,rest);
ans+=process(arr,index+1,rest-arr[index]);
return ans;
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int v=scan.nextInt();
int[] arr=new int[n];
scan.nextLine();
String[] s=scan.nextLine().split(" ");
long sum=0;
for(int i=0;i<n;++i) {
arr[i]=Integer.parseInt(s[i]);
sum+=arr[i];
}
if(sum<=v) System.out.println(1<<n);
else System.out.println(process(arr,0,v));
}
}
import java.util.Scanner;
public class Main{
public static int dpways(int[] arr,int v) {
//index:0~arr.length rest:0~v
int[][] dp=new int[arr.length+1][v+1];
for(int col=0;col<=v;++col) {
dp[arr.length][col]=1;
}
for(int row=arr.length-1;row>=0;--row) {
for(int col=0;col<=v;++col) {
dp[row][col]=dp[row+1][col];
if(col-arr[row]>=0) {
dp[row][col]+=dp[row+1][col-arr[row]];
}
}
}
return dp[0][v];
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int v=scan.nextInt();
int[] arr=new int[n];
scan.nextLine();
String[] s=scan.nextLine().split(" ");
for(int i=0;i<n;++i) {
arr[i]=Integer.parseInt(s[i]);
}
System.out.println(dpways(arr,v));
}
}
最小编辑代价
import java.util.Scanner;
public class Main {
public static int minEditCost(String s1,String s2,int ic,int dc,int rc) {
int[][] dp=new int[s1.length()+1][s2.length()+1];
for(int col=0;col<=s2.length();++col) {
dp[0][col]=col*ic;
}
for(int row=1;row<=s1.length();++row) {
dp[row][0]=row*dc;
}
for(int row=1;row<=s1.length();++row) {
for(int col=1;col<=s2.length();++col) {
//第一种可能性
if(s1.charAt(row-1)==s2.charAt(col-1)) {
dp[row][col]=dp[row-1][col-1];
}
else {
dp[row][col]=dp[row-1][col-1]+rc;
}
//第二种可能性
dp[row][col]=Math.min(dp[row][col], dp[row-1][col]+dc);
//第三种可能性
dp[row][col]=Math.min(dp[row][col], dp[row][col-1]+ic);
}
}
return dp[s1.length()][s2.length()];
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s1=scan.nextLine();
String s2=scan.nextLine();
int ic=scan.nextInt();
int dc=scan.nextInt();
int rc=scan.nextInt();
int ans=minEditCost(s1,s2,ic,dc,rc);
System.out.println(ans);
}
}
逻辑组合
import java.util.Scanner;
public class Main{
public static int process(String s,boolean desired,int L,int R) {
if(L==R) {
if(desired==true) {
return s.charAt(L)=='1'?1:0;
}else {
return s.charAt(L)=='1'?0:1;
}
}
int ans=0;
if(desired==true) {
for(int i=L+1;i<R;i+=2) {//以i位置的运算符结束
switch(s.charAt(i)) {
case '&':{
ans+=process(s,true,L,i-1)*process(s,true,i+1,R);
break;
}
case '|':{
ans+=process(s,true,L,i-1)*process(s,true,i+1,R);
ans+=process(s,true,L,i-1)*process(s,false,i+1,R);
ans+=process(s,false,L,i-1)*process(s,true,i+1,R);
break;
}
case '^':{
ans+=process(s,true,L,i-1)*process(s,false,i+1,R);
ans+=process(s,false,L,i-1)*process(s,true,i+1,R);
break;
}
}
}
}
else {
for(int i=L+1;i<R;i+=2) {//以i位置的运算符结束
switch(s.charAt(i)) {
case '&':{
ans+=process(s,true,L,i-1)*process(s,false,i+1,R);
ans+=process(s,false,L,i-1)*process(s,true,i+1,R);
ans+=process(s,false,L,i-1)*process(s,false,i+1,R);
break;
}
case '|':{
ans+=process(s,false,L,i-1)*process(s,false,i+1,R);
break;
}
case '^':{
ans+=process(s,true,L,i-1)*process(s,true,i+1,R);
ans+=process(s,false,L,i-1)*process(s,false,i+1,R);
break;
}
}
}
}
return ans;
}
public static long dpways(String s,boolean desired) {
//L:0~s.length()-1 R:0~s.length()-1
if(s.length()%2==0)return 0;
long[][] dpTrue=new long[s.length()][s.length()];
long[][] dpFalse=new long[s.length()][s.length()];
for(int i=0;i<s.length();i+=2) {
if(s.charAt(i)=='1') {
dpTrue[i][i]=1;
dpFalse[i][i]=0;
}else {
dpTrue[i][i]=0;
dpFalse[i][i]=1;
}
}
int N=1000000007;
for(int col=2;col<s.length();col+=2) {
for(int row=col-2;row>=0;row-=2) {
if(s.charAt(row)!='1'&&s.charAt(row)!='0'||s.charAt(col)!='1'&&s.charAt(col)!='0'){
//不合法的
return 0;
}
for(int k=row+1;k<col;k+=2) {
switch(s.charAt(k)) {
case '&':{
dpTrue[row][col]+=dpTrue[row][k-1]*dpTrue[k+1][col];
dpFalse[row][col]+=dpTrue[row][k-1]*dpFalse[k+1][col];
dpFalse[row][col]+=dpFalse[row][k-1]*dpTrue[k+1][col];
dpFalse[row][col]+=dpFalse[row][k-1]*dpFalse[k+1][col];
break;
}
case '|':{
dpTrue[row][col]+=dpTrue[row][k-1]*dpTrue[k+1][col];
dpTrue[row][col]+=dpTrue[row][k-1]*dpFalse[k+1][col];
dpTrue[row][col]+=dpFalse[row][k-1]*dpTrue[k+1][col];
dpFalse[row][col]+=dpFalse[row][k-1]*dpFalse[k+1][col];
break;
}
case '^':{
dpTrue[row][col]+=dpTrue[row][k-1]*dpFalse[k+1][col];
dpTrue[row][col]+=dpFalse[row][k-1]*dpTrue[k+1][col];
dpFalse[row][col]+=dpTrue[row][k-1]*dpTrue[k+1][col];
dpFalse[row][col]+=dpFalse[row][k-1]*dpFalse[k+1][col];
break;
}
}
dpTrue[row][col] %= 1000000007;
dpFalse[row][col] %= 1000000007;
}
}
}
if(desired)return dpTrue[0][s.length()-1]%N;
return dpFalse[0][s.length()-1]%N;
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String s=scan.nextLine();
boolean desired=scan.nextBoolean();
System.out.println(dpways(s,desired));
}
}
三个无重叠子数组的最大和
class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int[] dpleft=new int[nums.length];
int sum=0;
for(int i=0;i<k;++i) {
sum+=nums[i];
}
dpleft[k-1]=sum;
int[] add1=new int[nums.length];
add1[k-1]=sum;
for(int i=k;i<nums.length;++i) {
add1[i]=add1[i-1]-nums[i-k]+nums[i];
}
int[] left=new int[nums.length];
left[k-1]=0;
for(int i=k;i<nums.length;++i) {
if(dpleft[i-1]>=add1[i]) {
left[i]=left[i-1];
dpleft[i]=dpleft[i-1];
}else {
left[i]=i-k+1;
dpleft[i]=add1[i];
}
}
int[] right=new int[nums.length];
int[] dpright=new int[nums.length];
right[nums.length-k]=nums.length-1;
int[] add2=new int[nums.length];
sum=0;
for(int i=nums.length-1;i>=nums.length-k;--i) {
sum+=nums[i];
}
add2[nums.length-k]=sum;
for(int i=nums.length-k-1;i>=0;--i) {
add2[i]=add2[i+1]-nums[i+k]+nums[i];
}
right[nums.length-k]=nums.length-k;
dpright[nums.length-k]=add2[nums.length-k];
for(int i=nums.length-k-1;i>=0;--i) {
if(add2[i]>=dpright[i+1]) {
right[i]=i;
dpright[i]=add2[i];
}else {
right[i]=right[i+1];
dpright[i]=dpright[i+1];
}
}
int[] res=new int[3];
int max=Integer.MIN_VALUE;
for(int i=k;i<=nums.length-2*k;++i) {
int a=left[i-1];
int b=i;
int c=right[i+k];
if(add2[a]+add2[i]+add2[c]>max) {
max=add2[a]+add2[i]+add2[c];
res[0]=a;
res[1]=b;
res[2]=c;
}
}
return res;
}
}