• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【完全背包】LeetCode 1449. 数位成本和为目标值的最大数字

题目

https://leetcode.cn/problems/form-largest-integer-with-digits-that-add-up-to-target/description/

题解

因为每种面额的硬币能选的数量是没有限制的,因此这满足完全背包模型。

状态定义:定义一个大小为 \(target\) 的数组 \(dp\),每个节点用一个结构体维护三个整数 \(x, preffixIndex, length\)。\(dp[i]\) 代表当成本和为 \(i\) 时,所选的最后一个硬币的面值 \(x\),上一个选中的下标位置 \(preffixIndex\) 以及包含当前节点的长度为 \(length\);
状态转移方程:

\[dp[j] = \begin{cases} \{ i + 1, j - cost[i], dp[j-cost[i]].length+1 \}, & j-cost[i] \geq 0, dp[j-cost[i]].length+1>=dp[j].length \text{ 并且 } dp[j - cost[i]].x != 0 \\ dp[j], & others \end{cases} \]

参考代码

struct node {
    int x;// 所选的硬币面值
    int preffixIndex;// 上一个选中的下标位置,$0$ 代表没有上一个位置
    int length;// 包含当前节点的长度, $0$ 代表没有被选中的节点
};
class Solution {
public:
    string largestNumber(vector<int>& cost, int target) {
        string ans;
        vector<node> dp(target + 1);
        dp[0] = {1, 0, 0};// 将 dp[0].x 初始化为 1,让其它下标可以从 dp[0] 转移过去
        for (int i = 0; i < 9; ++ i) {// 一定要从小到大选,这样当遇到长度相同的情况时,必定可以覆盖,因为多选了一个面值较大的硬币
            for (int j = cost[i]; j <= target; ++ j) {// 执行状态转移
                int len = dp[j - cost[i]].length + 1;// 计算包含当前节点在内总共的长度
                if (len >= dp[j].length && dp[j - cost[i]].x != 0) {// 选中一个面值为 $(i + 1)$ 的硬币,并且从 $dp[j-cost[i]]$ 转移过来
                    dp[j] = {i + 1, j - cost[i], len};// 更新为更优的答案
                }
            }
        }
        for (int i = target; dp[i].length > 0; i = dp[i].preffixIndex) {// 逆序存入答案
            ans.push_back(dp[i].x + '0');
        }
        if (ans.empty()) ans = "0";// 不存在合法方案,根据题目要求返回 "0"
        return ans;
    }
};

posted on 2026-06-14 17:38  RomanLin  阅读(0)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3