小白懂的动态规划

本文介绍了动态规划在解决背包问题中的应用,包括01背包和完全背包。01背包问题中,每件物品只能使用一次,而完全背包允许无限次使用。通过示例代码详细解析了如何利用动态规划求解最大价值。同时,给出了LeetCode上的目标和问题及一和零问题的解决方案,展示了动态规划在实际问题中的转化与应用。

1. 动态规划之01背包

1.1. 纯01背包问题

问题描述

  有N件物品和一个最多能背重量为W的背包,第i件物品的重量为weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
  例如,三个物品:weight : {1,3,4},value: {15,20,30};背包容量:bagweight : 4

思路

代码

func totalValue(bagWeight int, weight []int, value []int ) int {
	dp := make([]int, bagWeight + 1)
	for i := 0; i < len(weight); i++ {
		for j := bagWeight; j >= weight[i]; j-- {
			dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
		}
	}
	return dp[bagWeight]
}

func max(a, b int) int {
	if a < b {
		a = b
	}
	return a
}


func main () {
	sc := bufio.NewScanner(os.Stdin)
	sc.Scan()
	bagWeight, _ := strconv.Atoi(sc.Text())

	sc.Scan()
	l1 := strings.Split(sc.Text(), ",")
	weight := make([]int, len(l1))
	for i := 0; i < len(l1); i++ {
		v, _ := strconv.Atoi(l1[i])
		weight[i] = v
	}

	sc.Scan()
	l2 := strings.Split(sc.Text(), ",")
	value := make([]int, len(l2))
	for i := 0; i < len(l2); i++ {
		v, _ := strconv.Atoi(l2[i])
		value[i] = v
	}

	fmt.Println(totalValue(bagWeight, weight, value))
}

1.2. LeetCode 494 目标和

问题描述

在这里插入图片描述
在这里插入图片描述

思路

  1. 将求目标和的问题,转换为背包问题
  2. 解背包问题

代码

	func findTargetSumWays(nums []int, target int) int {
	    var sum int
	    for i := 0; i < len(nums); i++ {
	        sum += nums[i]
	    }
	    if target > sum {
	        return 0
	    }
	    if ( sum + target ) % 2 == 1 {
	        return 0
	    }
	    
	    bagWeight := ( sum + target ) / 2
	    dp := make([]int, bagWeight + 1)
	    dp[0] = 1
	
	    for i := 0; i < len(nums); i++ {
	        for j := bagWeight; j >= nums[i]; j-- {
	            dp[j] += dp[j - nums[i]]
	        }
	    }
	    return dp[bagWeight]
	}

1.3. LeetCode474. 一和零

问题描述

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

在这里插入图片描述

思路

  1. 将问题转换为背包问题
  2. 构造背包weight数组
  3. 从2个维度遍历背包

代码

func findMaxForm(strs []string, m int, n int) int {
    var weight0 []int = make([]int, len(strs))
    var weight1 []int = make([]int, len(strs))
    
    dp := make([][]int, m + 1)
    for i := 0; i < m + 1; i++ {
        dp[i] = make([]int, n + 1)
    }

    for i := 0; i < len(strs); i++ {
        for j := 0; j < len(strs[i]); j++ {
            if strs[i][j] == '0' {
                weight0[i]++
            } else {
                weight1[i]++
            }
        }
    }

    for i := 0; i < len(strs); i++ {
        for j := m; j >= weight0[i]; j-- {
            for k := n; k >= weight1[i]; k-- {
                dp[j][k] = max(dp[j][k], dp[j - weight0[i]][k - weight1[i]] + 1)
            }
        }
    }
    return dp[m][n]
}

func max(a, b int) int {
    if a < b {
        a = b
    }
    return a
}

2. 动态规划之完全背包

  有N件物品和一个最多能背重量为W的背包,第i件物品的重量为weight[i],得到的价值是value[i]。每种物品在背包中可以放多个,求解将哪些物品装入背包里物品价值总和最大。

  01背包要求,每种物品在背包中只能用一次。完全背包和01背包不同的一点在于,每种物品在背包中可以有无限件。

  例如,三个物品:weight : {1,3,4},value: {15,20,30};背包容量:bagweight : 4

2.1. 纯完全背包问题

问题描述

  有N件物品和一个最多能背重量为W的背包,第i件物品的重量为weight[i],得到的价值是value[i]。每种物品在背包中可以放多个,求解将哪些物品装入背包里物品价值总和最大。

思路

  1. 遍历物体
  2. 遍历背包

代码

/**
    @author: HYK
    @date: 2021/6/17
    @email: flyingmonkey_hyk@163.com
    @note: Think Twice, Code Once!
**/
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func allBag(bagWeight int, weight []int, value []int ) int {
	dp := make([]int, bagWeight + 1)
	for i := 0; i < len(weight); i++ {
		for j := weight[i]; j <= bagWeight; j++ {
			dp[j] = mmax(dp[j], dp[j - weight[i]] + value[i])
		}
	}
	return dp[bagWeight]
}

func mmax(a, b int) int {
	if a < b {
		a = b
	}
	return a
}
func main () {
	sc := bufio.NewScanner(os.Stdin)
	sc.Scan()
	bagWeight, _ := strconv.Atoi(sc.Text())

	sc.Scan()
	l1 := strings.Split(sc.Text(), ",")
	weight := make([]int, len(l1))
	for i := 0; i < len(l1); i++ {
		v, _ := strconv.Atoi(l1[i])
		weight[i] = v
	}

	sc.Scan()
	l2 := strings.Split(sc.Text(), ",")
	value := make([]int, len(l2))
	for i := 0; i < len(l2); i++ {
		v, _ := strconv.Atoi(l2[i])
		value[i] = v
	}

	fmt.Println(allBag(bagWeight, weight, value))
}

2.2. Leetcode 518 零钱兑换II

问题描述

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

在这里插入图片描述
在这里插入图片描述

思路

完全背包

代码

func change(amount int, coins []int) int {
    dp := make([]int, amount + 1)
    dp[0] = 1

    for i := 0; i < len(coins); i++ {
        for j := coins[i]; j <= amount; j++ {
            dp[j] += dp[j - coins[i]]
        }
    }
    return dp[amount]
}
### 软件测试入门指南 #### 选择职业发展路线 对于希望进入软件测试领域的人来说,理解职业发展的不同路径非常重要。职业路径主要分为技术路线和管理路线两种。技术路线强调专业技能的发展,比如自动化测试工具的应用、性能测试技巧等;而管理路线则关注于团队协作能力和项目管理水平的提升[^1]。 #### 学习基础知识 为了打好坚实的基础,在开始之前应该先熟悉计算机科学基本概念,特别是编程语言(如Python)、数据库操作以及网络协议等方面的知识。这些将是后续深入研究的前提条件之一。 #### 掌握特定技能 针对具体岗位需求,还需要特别注意某些方面的训练: - **白盒测试**:这是一种依赖程序内部逻辑结构来进行检测的方法,要求从业者具备较强的编码能力以便能读甚至编写部分源码片段来辅助完成任务。这涉及到对函数调用关系图的理解及控制流分析等内容[^2]。 - **黑盒测试**:相对而言更加直观易一些,主要是站在最终用户的视角去检验应用程序的功能是否正常运作而不必关心其实现细节。此时要善于利用边界值法、等价类划分等策略构建有效的测试案例集。 - **自动化测试框架搭建**:随着DevOps理念日益普及,越来越多的企业倾向于采用CI/CD流水线作业模式加快产品迭代速度的同时保障质量稳定可靠。因此学会运用Selenium WebDriver这样的开源库实现UI层面上交互行为模拟变得尤为关键。 #### 实践经验积累 理论固然重要,但实际动手做才是王道。可以通过参与开源社区贡献代码审查意见或是加入本地的技术交流群组分享心得等方式快速成长起来。另外也可以考虑参加线上竞赛平台举办的Hackathon活动锻炼自己解决问题的能力。 #### 利用优质资源加速进步 互联网上有许多宝贵的自学材料可供参考借鉴。例如GitHub上面就存在一份详尽的大规模预训练模型学习手册,虽然其侧重点在于AI领域而非传统意义上的QA工程师培养方案,不过其中涉及的数据处理流程优化思路同样值得借鉴[^3]。 #### 关注行业动态保持敏感度 最后一点就是时刻留意业界最新趋势变化,订阅几份权威性的资讯网站邮件列表不失为一种不错的选择。这样不仅能及时获取到有关新兴技术和最佳实践经验的信息更新推送通知,而且有助于拓宽视野范围从而更好地规划个人长远发展目标。 ```python # Python脚本用于执行简单的单元测试 import unittest class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('foo'.upper(), 'FOO') if __name__ == '__main__': unittest.main() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值