首页 > 其他分享 >代码随想录day36 || 1049 最后一筐石头重量||, 494 目标和,474 一和零

代码随想录day36 || 1049 最后一筐石头重量||, 494 目标和,474 一和零

时间:2024-08-21 11:48:44浏览次数:13  
标签:target nums day36 sum 随想录 int 474 var dp

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用户

image

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 一和零

image

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
}

标签:target,nums,day36,sum,随想录,int,474,var,dp
From: https://www.cnblogs.com/zhougongjin55/p/18371312

相关文章

  • 「代码随想录算法训练营」第四十三天 | 图论 part1
    797.所有可能的路径题目链接:https://leetcode.cn/problems/all-paths-from-source-to-target/description/文章讲解:https://programmercarl.com/kamacoder/0098.所有可达路径.html题目难度:中等题目状态:看题解思路一:DFSvoiddfs(vector<vector<int>>&graph,intx,intn......
  • 代码随想录Day21
    669.修剪二叉搜索树给你二叉搜索树的根节点root,同时给定最小边界low和最大边界high。通过修剪二叉搜索树,使得所有节点的值在[low,high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。可以证明,存在唯一的答案。所......
  • 「代码随想录算法训练营」第四十二天 | 单调栈 part2
    42.接雨水题目链接:https://leetcode.cn/problems/trapping-rain-water/文章讲解:https://programmercarl.com/0042.接雨水.html题目难度:困难视频讲解:https://www.bilibili.com/video/BV1uD4y1u75P/题目状态:这道题目在LeetCodeTop100中做过,使用两种方法,再回顾一下思路一:单......
  • 代码随想录day35 || 416 分割等和子集
    背包问题有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。//pake//// @Description:// @paramweights:物品i对应重量// @paramvalue:物品i对应价值// @......
  • 「代码随想录算法训练营」第四十一天 | 单调栈 part1
    739.每日温度题目链接:https://leetcode.cn/problems/daily-temperatures/文章讲解:https://programmercarl.com/0739.每日温度.html题目难度:中等视频讲解:https://www.bilibili.com/video/BV1my4y1Z7jj/题目状态:看题解思路:定义一个单调栈,该栈存放下标,规则是要保持其下标对......
  • 代码随想录day34 || 62 不同路径,63 不同路径||,343整数拆分,96 不同搜索二叉树
    不同路径funcuniquePaths(mint,nint)int{ //dp五部曲 //dp数组以及下标的含义dp[i][j]代表从0,0走到i,j的不同路径条数 //递推公式 dp[i][j]=dp[i-1][j]+dp[i][j-1] //dp数组的初始化dp[i][0]==dp[0][j]=1 //遍历顺序 外层按照行,内层按照列遍历......
  • 代码随想录Day18
    530.二叉搜索树的最小绝对差给你一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值。差值是一个正数,其数值等于两值之差的绝对值。示例1:输入:root=[4,2,6,1,3]输出:1示例2:输入:root=[1,0,48,null,null,12,49]输出:1提示:树中节点的数目范围是......
  • 代码随想录算法训练营第11天|二叉树part01
    理论基础需要了解二叉树的种类,存储方式,遍历方式以及二叉树的定义二叉树纯理论方面还是比较简单,以前都学过,没什么可讲的。满二叉树就是满了,完全二叉树就是层满了(而且是左边)。平衡二叉搜索树就是左右深度绝对值差1。一般采用链式存储方式,顺序存储结构如果父节点的数组......
  • 代码随想录算法训练营第10天|栈与队列part02
    150.逆波兰表达式求值本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题classSolution{public:intevalRPN(vector<string>&tokens){stack<longlong>st;for(conststring&token:tokens){if(token=="+......
  • 代码随想录Day17
    654.最大二叉树给定一个不重复的整数数组nums。最大二叉树可以用下面的算法从nums递归地构建:创建一个根节点,其值为nums中的最大值。递归地在最大值左边的子数组前缀上构建左子树。递归地在最大值右边的子数组后缀上构建右子树。返回nums构建的最大二叉树......