一、动态规划
- 本质:
- 题目条件: 出现每次只能向下或者向右移动一步 。
二、思路
-
关键词:
-
难点在于:
- 定义dp[i][j] 一般要求什么就是把dp[i][j]定义为啥
- 寻找转换关系 即当前dp[i][j]的结果取自哪里?在路径问题中,一般看到其移动路径,即可确定状态转移方程。比如“只能向下或者向右移动”,则说明dp[i][j]来自dp[i-1][j]或者dp[i][j-1]
- 确定初始值
三、题目汇总
四、题解汇总
- Code 416
解法一:使用回溯,超时
func canPartition(nums []int) bool {
sum:=0
for i:=0;i<len(nums);i++{
sum=sum+nums[i]
}
sort.Ints(nums)
target:=sum/2
if sum%2!=0{
return false
}
return dfs(nums,0,0,target)
}
func dfs(nums []int, index int,sum int,target int)bool{
if sum==target{
return true
}
if index>=len(nums) || sum>target{
return false
}
for i:=index;i<len(nums);i++{
if dfs(nums,i+1,sum+nums[i],target){
return true
}
}
return false
}
解法二:动态规划
func canPartition(nums []int) bool {
// dp[i][j]表示从下标范围[0,i]内选取若干个元素,是否存在一种方案使得和为j
// 变化的是:数组中的元素索引、数组元素的和
// dp[i][j]=dp[i-1][j]& dp[i-1][j-nums[i]]
// dp[i][0]=true dp[0][nums[0]=true
if len(nums)<2{
return false
}
sum:=0
max:=nums[0]
for i:=0;i<len(nums);i++{
sum=sum+nums[i]
if nums[i]>max{
max=nums[i]
}
}
target:=sum/2
if max>target{
return false
}
if sum%2!=0{
return false
}
dp:=make([][]bool,len(nums))
for i:=0;i<len(nums);i++{
dp[i]=make([]bool,target+1)
}
dp[0][0]=true
dp[0][nums[0]]=true
for i:=1;i<len(nums);i++{
for j:=0;j<=target;j++{
//分两种:选取i或者不选取i
if j>=nums[i]{
dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]]
}else{ //无法选取i
dp[i][j]=dp[i-1][j]
}
}
}
return dp[len(nums)-1][target]
}