LeetCode279. 完全平方数 DP完全背包

news2024/10/6 1:46:06
  • https://leetcode.cn/problems/perfect-squares/

题目描述

  • 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量。
    完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4
示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9
class Solution {
public:
    int numSquares(int n) {

    }
};

完全背包

  • 恰好装满之类的01背包问题,竖向i是物品,横向j是容量。 i为前i件物品,容量j可以为0,算法主题为遍历i,j 。
    由于无后效性,只知道nums[i],需要判断j-nums[i]能做什么。
    j-nums[i]为装了当前物品剩余的空间。dp[ i-1][j-nums[i]]为这点空间能做的事情。如果最大化利润则为以下公式:
    d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − w i ] + v i ) dp[i][j]=max(dp[i−1][j],dp[i][j−w _i ]+v_i ) dp[i][j]=max(dp[i1][j],dp[i][jwi]+vi)

  • 完全背包每次还是考虑当前项,只不过可以拿多个,那我们可以加个循环k
    d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w i ∗ k ] + v i ) dp[i][j]=max(dp[i−1][j],dp[i-1][j−w _i\color{red}*k\color{black} ]+v_i ) dp[i][j]=max(dp[i1][j],dp[i1][jwik]+vi)

  • 实际上j是从小到大遍历的,所以可以用
    d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − w i ] + v i ) dp[i][j]=max(dp[i−1][j],dp[\color{red}i\color{black}][j−w _i ]+v_i ) dp[i][j]=max(dp[i1][j],dp[i][jwi]+vi)
    省略掉一个循环

  • 0-1背包如果压缩维度dp[i][j-nums[i]],但是j需要倒序遍历。

完全背包

        完全背包是一类经典的背包问题,与0/1背包问题和多重背包问题不同。其中,每个物品可以被无限次地选择放入背包。也就是说,每个物品的数量是无限的。

        假设有一个容量为 V V V的背包,现在有 n n n个物品,每个物品的体积为 w i w_i wi,价值为 v i v_i vi,同时每个物品的数量是无限的。问能够放入背包的最大价值是多少?

        完全背包问题可以通过动态规划求解,时间复杂度为 O ( n V ) O(nV) O(nV)。可以用一个二维数组 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示前 i i i个物品放入容量为 j j j的背包中获得的最大价值。其中,状态转移方程为 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − w i ] + v i ) dp[i][j]=max(dp[i-1][j],dp[i][j-w_i]+v_i) dp[i][j]=max(dp[i1][j],dp[i][jwi]+vi),表示当前物品不放入背包或者放入背包均可。

  • (二维的转移方程还是比较好记的,只需要将 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w i ] + v i ) dp[i][j]=max(dp[i-1][j],dp[\color{red}i-1\color{black}][j-w_i]+v_i) dp[i][j]=max(dp[i1][j],dp[i1][jwi]+vi)写成i就行)

13 = 9 = 3 \sqrt {13} = \sqrt{9} = 3 13 =9 =3

012345678910111213
1
2
3

" 能够放入背包的最大价值 " ⇒ " 能够放入背包的最小价值 " ( 每个数的价值为 1 ) "能够放入背包的最大价值" \Rightarrow "能够放入背包的最小价值"\tiny(每个数的价值为1) "能够放入背包的最大价值""能够放入背包的最小价值"(每个数的价值为1)
d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − w i ] + v i ) dp[i][j]=max(dp[i-1][j],dp[i][j-w_i]+v_i) dp[i][j]=max(dp[i1][j],dp[i][jwi]+vi)

在这里插入图片描述
d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − w i ] + 1 ) dp[i][j]=min(dp[i-1][j],dp[i][j-w_i]+1) dp[i][j]=min(dp[i1][j],dp[i][jwi]+1)

class Solution {
public:
    // 求平方后小于 n 的最大完全平方数
    int min_sq(int n) {
        int ans = 1;
        for ( int i=1;i<n;i++ ) {
            if ( i*i>n )
                break;
            ans = i;
        }
        return ans;
    }

    int numSquares(int n) {

        // // 记忆化搜索
        // int m = min_sq(n), cache[m+1][n+1];
        // memset(cache, -1, sizeof(cache));
        // function<int(int,int)> dfs = [&](int i, int c) -> int {
        //     if ( i<0 )
        //         return c==0 ? 0 : INT_MAX/2;
        //     if ( cache[i][c]!=-1 )
        //         return cache[i][c];
        //     if ( c<(i+1)*(i+1) )
        //         return cache[i][c] = dfs(i-1, c);
        //     return cache[i][c] = min(dfs(i-1, c), dfs(i, c-(i+1)*(i+1))+1);
        // };

        // return dfs(m-1, n);

        // // 1:1 递推
        // int m = min_sq(n), f[m+1][n+1];
        // memset(f, 0x3f, sizeof(f));
        // f[0][0] = 0;
        // for ( int i=0;i<m;++i ) {
        //     for ( int c=0;c<n+1;++c ) {
        //         if ( c<(i+1)*(i+1) )
        //             f[i+1][c] = f[i][c];
        //         else
        //             f[i+1][c] = min(f[i][c], f[i+1][c-(i+1)*(i+1)]+1);
        //     }
        // }
        // return f[m][n];

        // // 滚动双数组空间优化
        // int m = min_sq(n), f[2][n+1];
        // memset(f, 0x3f, sizeof(f));
        // f[0][0] = 0;
        // for ( int i=0;i<m;++i ) {
        //     for ( int c=0;c<n+1;++c ) {
        //         if ( c<(i+1)*(i+1) )
        //             f[(i+1)%2][c] = f[i%2][c];
        //         else
        //             f[(i+1)%2][c] = min(f[i%2][c], f[(i+1)%2][c-(i+1)*(i+1)]+1);
        //     }
        // }
        // return f[m%2][n];

        // 单数组空间优化
        int m = min_sq(n), f[n+1];
        memset(f, 0x3f, sizeof(f));
        f[0] = 0;
        for ( int i=0;i<m;++i ) {
            for ( int c=0;c<n+1;++c ) {
                if ( c>=(i+1)*(i+1) )
                    f[c] = min(f[c], f[c-(i+1)*(i+1)]+1);
            }
        }
        return f[n];
    }
};

// 作者:thirikid
// 链接:https://leetcode.cn/problems/perfect-squares/solution/ling-shen-wan-quan-bei-bao-hui-su-ji-yi-d48mb/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一维

这个问题可以通过动态规划求解。我们可以用一个一维数组 d p dp dp 来表示和为 i i i 的完全平方数的最少数量,状态转移方程为:

d p [ i ] = min ⁡ j = 1 i { d p [ i − j 2 ] + 1 } dp[i] = \min_{j=1}^{\sqrt{i}} \{dp[i-j^2] + 1\} dp[i]=j=1mini {dp[ij2]+1}

其中, j j j 表示一个完全平方数, i − j 2 i-j^2 ij2 表示剩余的部分。也就是说,要计算和为 i i i 的完全平方数的最少数量,我们需要枚举最后一个完全平方数 j j j,并计算剩余部分 i − j 2 i-j^2 ij2 的最少数量,最后加上 1 即可。

初始状态为 d p [ 0 ] = 0 dp[0] = 0 dp[0]=0,因为和为 0 0 0 的完全平方数数量为 0 0 0

最终的答案为 d p [ n ] dp[n] dp[n]。以下是Python代码实现:

def numSquares(n: int) -> int:
    # 初始化状态
    dp = [float('inf')] * (n + 1)
    dp[0] = 0

    # 状态转移
    for i in range(1, n+1):
        for j in range(1, int(i ** 0.5) + 1):
            dp[i] = min(dp[i], dp[i - j*j] + 1)

    return dp[n]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/645182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python类中常用的魔术方法

文章目录 构造方法__init__对象转字符__str__对象自定义大小比较First__lt__Second__le__Third__eq__ 构造方法__init__ 构造方法也是魔术方法的一种&#xff0c;此方法我在python对象与类中已经展示过了 注意&#xff1a;在方法中引用类成员变量一定要记得使用self关键字引用…

Elasticsearch:倒数排序融合 - Reciprocal rank fusion

警告&#xff1a;此功能处于技术预览阶段&#xff0c;可能会在未来版本中更改或删除。 Elastic 将尽最大努力修复任何问题&#xff0c;但技术预览中的功能不受官方 GA 功能的支持 SLA 约束。 倒数排序融合&#xff08;RRF&#xff09;是一种将具有不同相关性指标的多个结果集组…

蓝牙资讯|Canaly发布2023Q1全球可穿戴腕带设备报告

根据市场调查机构 Canalys 公布的最新报告&#xff0c;2023 年第 1 季度全球可穿戴腕带设备出货量为 4100 万台&#xff0c;同比下降 1%。 其中&#xff0c;本季度全球基础手环市场受到厂商和消费者更关注大屏设备影响&#xff0c;出货量为 750 万台&#xff0c;同比下降 24%…

Vue中如何进行拖拽与排序功能实现

Vue中如何进行拖拽与排序功能实现 在Web应用程序中&#xff0c;拖拽和排序功能是非常常见的。在Vue中&#xff0c;我们可以使用一些组件库来实现这个功能&#xff0c;例如sortablejs和vuedraggable。本文将介绍如何使用vuedraggable组件来实现Vue中的拖拽和排序功能。 什么是v…

Selenium Python教程第7章:Selenium编程其它功能

7. Selenium其它功能 7.1 Action Chains 动作链功能 WebDriver只能模拟针对特定元素的click, send_keys 操作&#xff0c;无法执行鼠标移动、悬浮、按键&#xff0c;选择菜单等操作&#xff0c;需要通过 Action Chains 类来操作 如下面操作&#xff0c;打开主菜单项后&#x…

实战:用dockerfile创建镜像实现springboot项目容器化

文章目录 前言技术积累docker基本操作命令dockerfile简介dockerfile指令说明 实战演示创建dockerfile创建挂载目录构建dockerfile启动容器完成验证 写在最后 前言 docker容器化方案是当下流行的服务部署方式&#xff0c;在软件领域举足轻重。我公司的测试、线上环境都采用dock…

选择最适合你的云服务器:腾讯云、华为云、阿里云对比

云服务器是一种基于云计算技术的服务器&#xff0c;它可以为企业提供高效、灵活、安全的运行环境。目前市场上有很多云服务器的选择&#xff0c;其中腾讯云、华为云和阿里云是最受欢迎的三个品牌&#xff0c;下面我们来看看它们各自的优势。 腾讯云的优势在于其强大的技术支持…

谷粒商城p45-自动装配-stream流-lambda表达式

软件&#xff1a;idea、postman、virtual box 服务&#xff1a;gulimall-product 请求路径&#xff1a;http://localhost:10000/product/category/list/tree 启动&#xff1a;启动idea product模块&#xff0c;启动vm&#xff0c;启动docker mysql controller代码 自动装配C…

LeetCode494. 目标和 0-1背包DP

https://leetcode.cn/problems/target-sum/ 题目描述 给你一个整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 ‘’ 或 ‘-’ &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在…

网络传输中的那些编码之-UTF8编码漫谈

编码为什么是一个重要的话题&#xff0c;因为我们和计算机交互的主要方式目前还是文字字符。作为一个程序员&#xff0c;相信大部分都都被字符和编码的问题折磨过&#xff0c;从键盘输入文字字符到编辑器 中&#xff0c;编辑器存储字符到硬盘&#xff0c;再到具体一个编程语言如…

中国电子学会2023年05月份青少年软件编程Scratch图形化等级考试试卷二级真题(含答案)

2023-05 Scratch二级真题 题数&#xff1a;37 分数&#xff1a;100 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1.运行下列哪段程序&#xff0c;可以让狗狗走到木屋门口&#xff1f;&#xff08;C&#xff09;(2分) A. B. C. D. 答案解析&a…

我用AI提高我的代码质量,周边同事对我的代码赞不绝口,速来围观

文章目录 前言功能演示1.使用Stream API来简化集合操作2.使用switch语句来替代多个if-else语句3.使用try-with-resources语句来自动关闭资源4. Lambda 表达式来简化代码,并提高代码的可读性和可维护性5.查找代码中的bug并优化6.python 使用sort方法来对列表进行排序7.javaScrpi…

一文看懂MySQL是什么

你可以前往我的博客查看更多关于云服务器和数据库以及域名注册、建站等相关文章。 MySQL是一种开源关系型数据库管理系统&#xff0c;它是最受欢迎的数据库之一。MySQL是由瑞典公司MySQL AB创建的&#xff0c;后来被Sun Microsystems收购&#xff0c;现在是Oracle Corporation…

Flink 系列二 Flink 状态化流处理概述

本篇作为Flink系列的第二篇&#xff0c;第一篇是环境准备&#xff0c;需要的同学可以看&#xff1a;https://blog.csdn.net/lly576403061/article/details/130358449?spm1001.2014.3001.5501。希望可以通过系统的学习巩固该方面的知识&#xff0c;丰富自己的技能树。废话不多说…

解决 org.eclipse.jface.text.Document class file version 61.0 报错

问题描述 运行好好的项目&#xff0c;没有做任何改动&#xff0c;最近在编译时报以下错误 java.lang.UnsupportedClassVersionError: org/eclipse/jface/text/Document has been compiled by a more recent version of the Java Runtime (class file version 61.0), this vers…

解决Python使用pip安装库文件出现“ERROR: Cannot unpack file…”

解决问题 1 ERROR: Could not find a version that satisfies the requirement robotframework (from versions: none) ERROR: No matching distribution found for robotframework 在dos命令输入 pip install robotframework 在线安装robotframework 如下报错&#xff1a; …

在紧急情况下,120可以定位我们的位置吗

随着科技的快速发展&#xff0c;越来越多的人们开始意识到科技对于生活的重要性。在现代社会中&#xff0c;GPS定位系统已经成为了一个不可或缺的工具&#xff0c;并且被广泛应用于各个领域&#xff0c;包括医疗救援行业。 120急救车和120急救指挥调度系统都采用了GPS定位技术…

SpringCloud Eureka注册中心高可用集群配置(八)

当注册中心扛不住高并发的时候&#xff0c;这时候 要用集群来扛&#xff1b; 我们再新建两个module microservice-eureka-server-2002 microservice-eureka-server-2003 第一步&#xff1a; pom.xml 把依赖加下&#xff1a; <dependencies> <dependency…

失败的统一错误处理

1.拦截器 在调用接口的时候,客户端会向服务器发送请求,请求之前有请求拦截器&#xff0c;返回数据之前有响应拦截器。 2:示例 根据自己的状态码来进行判断的一般2字开头代表成功&#xff0c;这个状态码是由后端来进行控制的。 成年的代码处理: if (res.data.success) {// 成功…

都是被逼的... ,LM算法的具体实现python和C++代码

L-M方法全称Levenberg-Marquardt方法&#xff0c;是一种非线性最小二乘优化算法&#xff0c;它通过同时利用高斯牛顿方法和梯度下降方法来解决非线性最小二乘问题。其核心思想是在每次迭代中&#xff0c;根据当前参数估计计算目标函数的梯度和海森矩阵&#xff0c;并使用这些信…