1049 最後一塊石頭重量||
func lastStoneWeightII(stones []int) int {
// 本題思路在於要想得到最小差,就要儘可能將石頭分割為兩堆相近的重量,然後轉換為揹包問題
// dp[i] 表示容量i揹包能裝的石頭總價值,其中重量和價值相等
// 遞推公式 dp[j] = max(dp[j], dp[j-w(i)] + v[i]) == max(dp[j], dp[j-s[i]]+s[i])
// 初始化 dp[0] = 0
// 遍歷順序,先正序物品, 後倒敘揹包,原因在於遞推公式依賴於上一層dp的狀態推導,所以正序可能導致之前的元素被覆蓋出現錯誤
// print
var sum, mid int
for _, v := range stones{
sum += v
}
mid = sum / 2
var dp = make([]int, mid + 1)
for i:=0; i<len(stones); i++ {
for j:=mid; j>0; j-- {
if j-stones[i] >= 0{
dp[j] = max(dp[j], dp[j-stones[i]]+stones[i])
}
}
}
//fmt.Println(dp)
return sum - 2*dp[mid] // sum - dp[mid] 代表另一半石頭的重量,然後兩半相減得到的就是最小差
}
494 目標和
var path []int
var res int
var mutil = []int{-1, 1}
func findTargetSumWays(nums []int, target int) int {
// 思考一下回溯辦法
// 回溯三部曲,引數以及返回值,終止條件,回溯遍歷過程
path = make([]int, 0)
res = 0
backTracking(nums, target, len(nums))
return res
}
func backTracking(nums []int, target, length int ) {
if len(path) == length{
//fmt.Println(path)
if sum(path) == target{
res += 1
}
return
}
for i:=0; i<len(nums); i++{
for _, v := range mutil{ // 每一個元素遍歷兩個,分別插入正數負數,結束時回溯
path = append(path, v*nums[i])
backTracking(nums[i+1: ], target, length )
path = path[0: len(path) - 1]
}
break // !!!!!這裡剪枝的目的是儘可能保障path長度為len(nums),如果將首個元素去除的話,長度肯定小於len(nums),所以剪枝
}
}
func sum(n []int) int {
var s int
for _, v := range n {
s += v
}
return s
}
// 回溯法超時
// 剪枝之後壓線透過
執行耗時:1897 ms,擊敗了5.04% 的Go使用者
記憶體消耗:2.2 MB,擊敗了69.39% 的Go使用者
func findTargetSumWays(nums []int, target int) int {
// 將陣列劃分為正數陣列和負數陣列 推匯出正數陣列 = (sum + target) / 2
// dp[i][j] 代表儘可能裝滿容量為j的揹包的方法數量
// 遞推:dp[i][j] = dp[i-1][j] + dp[i-1][j-w(j)] 代表不裝j的方法數 + 裝j的方法數
// 初始化 dp[1][1] =1
// 遍歷順序,隨意
// print
var sum int
for _, v := range nums {
sum += v
}
if ( sum + target ) % 2 == 1 || float64(sum) < math.Abs(float64(target)) {
return 0
}
mid := (sum + target) / 2
var dp = make([][]int, len(nums) + 1)
for idx, _ := range dp {
dp[idx] = make([]int, mid + 1)
}
dp[0][0] = 1
for i:=0; i<len(nums); i++ {
for j:=0; j<=mid; j++{
//fmt.Println(i+1, j, dp[i][j], dp[i][j-nums[i]])
dp[i+1][j] = dp[i][j]
if j - nums[i] >= 0 {
dp[i+1][j] += dp[i][j-nums[i]]
}
}
}
//fmt.Println(dp)
return dp[len(nums)][mid]
}
474 一和零
func findMaxForm(strs []string, m int, n int) int {
// 此處難點在於二維的0-1揹包
// dp[i][j] 代表儘可能裝滿i個0,j個1的揹包能獲得的最大價值,由於價值等於數量*1 所以也是最大數量
// 遞推公式 dp[i][j] = max(dp[i][j], dp[i-x][j-y] + 1) // x,y分別代表字元0,1數量
// 初始化全部為0
// 遍歷順序,先正序物品,後倒敘揹包,由於是滾動陣列,所以dp陣列依賴的是上一層的dp值,如果正序會覆蓋上一層,所以不能正序
// print
var dp = make([][]int, m+1)
for idx, _ := range dp{
dp[idx] = make([]int, n+1)
}
for _, str := range strs {
var x, y int
for i:=0; i<len(str); i++ {
if str[i] == '0'{
x++
}
if str[i] == '1'{
y++
}
}
for i:=m; i>=x; i--{
for j:=n; j>=y; j--{
dp[i][j] = max(dp[i][j], dp[i-x][j-y] + 1)
}
}
}
//fmt.Println(dp)
return dp[m][n]
}
func max (i, j int) int {
if i>j{
return i
}
return j
}