算法题解记录17+++完全平方数

news2024/11/25 0:23:37

        这是楼主第一次不靠题解,挑战动态规划的中等题目,虽然最终结果只超过了5%的人,不过我也很满意了。

        本题楼主首先采用朴素的递归型动态规划,接着优化算法,使用借助HashMap存储临时数据的递归型动态规划,几次时间复杂度都很高,最后优化成借助数组存储数据的迭代型动态规划。

题目描述:

        给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

        完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

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

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

提示:

  • 1 <= n <= 10^4

解题准备:

        1.了解可能存在的基础操作:首先,输入只有一个数,应该不会有查找【事实证明,还是有,而且得自己建立数据结构】;;其余看不出来。

        2.理解题意:其实用朴素的观点,很容易想到一种解法---对于数据i,先找到i以下的最大平方数(比如10,找到9;或者17,找到16),接着,用i-这个数得到新的i,再用新的i继续此过程,直到i==1,返回一共执行的次数。

                不过,这个思路是错误的!

                假设i==12,按照此思路,第一步是i-9,得到i=3,接着i==3依次-1,一共执行了4次,返回4;;然而,答案是12=4+4+4,只需要执行3次。

        那么,还有其它思路吗?

        我们想处理i的完全平方数,需不需要借助i-1、i-2……的完全平方数数据呢?

        我们直接处理i,可能有几种情况?

解题难点1分析:

        对解题准备的问题进行思考,我们可以发现:

        处理i的情况:

                1.如果i是完全平方数,比如1,4,9,16,25……那么直接返回1;

                2.如果i不是完全平方数,那么可能会有无数种情况(比如刚刚的12=4+4+4),一下子没法处理。

                作图如下:

                我们可以发现,2的最少完全平方数,就是1+1;

                3的最少完全平方数,是1+1+1,形式上等于1+2,并且数目上,1的最少完全平方数和2的最少完全平方数之和,就等于3的最少完全平方数。

                不过,对于4不同,对于5好像也不太符合。

                继续观察,我们发现,5的最少完全平方数,是4+1,形式上和数目上,都等于1的最少完全平方数+4的最少完全平方数。

                其实,如果i不是完全平方数,那么i可以转化为k+n(i=k+n,k、n>=1),如果使k、n最少完全平方数的和最小,就能得到i的最少完全平方数。

                比如i是100,那么就从k=1,一直遍历到k=99【当然,为了省时、避免重复,遍历到k=50就差不多】

                即i=100, k=1, n=99;

                i=100, k=2, n=98;

                i=100, k=3, n=97;

                ……

                i=100, k=50, n=50;

                这本质上是一种暴力搜索,把所有情况枚举出来,然后选择最少的一个。

        原始动态规划递归代码:

                我们既然知道了,求i,就得求k+n,又因为k、n>=1,所以k、n必然小于i,那么,只要得到从1到i-1的所有最少完全平方数,就能枚举得到i的最少完全平方数。

                求i-1、i-2的最少完全平方数,其结构与求i的类似,所以我们可以使用递归的方法解决。

class Solution {
   public int numSquares(int n) {
        int res=n;

        // 判断是否完全平方数
        double temp=Math.sqrt(n);
        int l=(int)temp;
        if(l-temp==0){
            return 1;
        }

        // 遍历得到从1到i-1的所有最少完全平方数
        for(int i=1; i<n/2+1; i++){
            res=Math.min(res, numSquares(n-i)+numSquares(i));
        }
    
        return res;
    }
}

        这个算法,时间复杂度奇高,由于需要从1到n/2+1,每次调用两个自身(n-i和i),所以可以把递归树看成一个二叉树,该树的深度约为n,且基本上是满二叉树,其时间复杂度可想而知。

        我也不确定时间复杂度,不过我猜是O(n/2 * 2^n);

        HashMap临时存储动态规划代码:

class Solution {
   // 存储临时数据
   Map<Integer, Integer> data=new HashMap<>(); 
   public int numSquares(int n) {
        int res=n;

        // 判断是否为完全平方数
        double temp=Math.sqrt(n);
        int l=(int)temp;
        if(l-temp==0){
            return 1;
        }

        // 同样的递归,实质一样,不过先从临时数据中查看有无
        for(int i=1; i<n/2+1; i++){
            if(data.get(i)!=null){
                if(data.get(n-i)!=null){         
                    res=Math.min(res, data.get(i)+data.get(n-i));
                }else{
                    res=Math.min(res, data.get(i)+numSquares(n-i));
                }
            }else if(data.get(n-i)!=null){
                res=Math.min(res, data.get(n-i)+numSquares(i));
            }else{
                res=Math.min(res, numSquares(n-i)+numSquares(i));
            }
        }

        data.put(n, res);
        return res;
    }
}

                这个算法,节省至少一半的时间,实质上,由于把从1到i-1的数据都保存了,应该能使复杂度到O(n/2 * n!);

解题难点2分析:

        不过,即使是竭尽所能,时间上仍然超出限制。

        所以,不得不考虑更加复杂的迭代型动态规划。

        根据上述思路,我们已经知道如何处理i,那么,怎么处理1到i-1,并存储起来呢?

        首先,已知,对于i这个大问题,只要它不是完全平方数,解法就是拆分成两个数,然后求出所有解,拿到最小的一个。

        那么,第一步,至少得有两个基本数据,一般选取1、2作为基本数据。

        接着,我们需要一个数据结构来存储基本数据,比如HashMap,我采用的是数组,其随机访问的特性非常有用。

        声明数组dp,就得知道它多大,从1存储到i-1,所以是i-1这么大。为了保险,选取i作为大小。

        此时,满足dp[0]=1, dp[1]=2;

        接下来,就是遍历运算。

        按理说,对于数据i,i=k+n,所以只需要从k=1,遍历到i/2+1即可得到其最少完全平方数。

        数组存储的动态规划代码:

class Solution {
   public int numSquares(int n) {
        int[] dp=new int[n]; // 声明数组
        int res=n; // 保险起见

        // 判断是否为完全平方数
        double temp=Math.sqrt(n);
        int l=(int)temp;
        if(l-temp==0){
            return 1;
        }

        // 从3开始,因为1、2已经得到
        int i=3;
        dp[0]=1;
        dp[1]=2;

        // i<n,即遍历到n-1
        while(i<n){
            // 在遍历时,不可避免地可能存在完全平方数
            temp=Math.sqrt(i);
            l=(int)temp;
            if(l-temp==0){
                dp[i-1]=1;
                i++;
                // 记得continue,否则执行下面的语句后,出错
                continue;
            }

            // 保险
            res=i;

            // 迭代得到最少完全平方数
            for(int k=1; k<i/2+1; k++){
                res=Math.min(res, dp[k-1]+dp[i-k-1]);
            }
            // 记录
            dp[i-1]=res;
            i++;
        }

        // 拿到真实结果
        res=n;
        for(int ln=1; ln<n/2+1; ln++){
            res=Math.min(res, dp[ln-1]+dp[n-ln-1]);
        }
        return res;
    }
}

        题解的思路则非常简洁,我会在接下来的算法补充中说明。

        以上内容即我想分享的关于力扣热题17的一些知识。

        我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

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

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

相关文章

攻防世界15:xff-referer

首先需要了解什么是xff--代理服务器&#xff0c;通过代理访问服务器&#xff0c;referer:HTTP REFERER 是hesder的一部分&#xff0c;当浏览器向web服务器发送请求的时候&#xff0c;一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的&#xff0c;服务器因此可以获得一…

数据结构--顺序表(C语言版)

&#xff08;一&#xff09;.顺序表的概念及结构 首先&#xff0c;我们来了解一下什么是数据结构呢&#xff1f; 数据结构是顾明思义就是由数据结构。 常⻅的数值1、2、3、4.....、教务系统⾥保存的⽤⼾信息&#xff08;姓名、性别、年龄、学历等 等&#xff09;、⽹⻚⾥⾁眼…

基于SSM的列车订票管理系统(含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的列车订票管理系统3拥有两种角色&#xff1b;管理员、用户 管理员&#xff1a;用户管理、车票管理、购票指南管理、系统管理等 用户&#xff1a;发布帖子、登录注册、购票等 1.…

洲宇新作 成都越秀·天悦云萃,献给城市的作品

筑是生活的镜子”——贝聿铭 建筑&#xff0c;往往折射一个时代的审美 随着城市快速扩张时代正在逐渐走向结束&#xff0c;各城市发展回归主城中心&#xff0c;高价值的主城区域正在掀起新的时代。新时代高净值置业者从追求奢华与气派到回归住宅的本质与需求。首先产品不仅要满…

机器学习鸢尾花各种模型准确率对比

流程 获取数据集导入需要的包读取数据划分训练集和测试集调用各种模型比较准确率 获取数据集 链接&#xff1a;https://pan.baidu.com/s/1RzZyXsaiJB3e611itF466Q?pwdj484 提取码&#xff1a;j484 --来自百度网盘超级会员V1的分享导入需要的包 import pandas as pd impo…

C语言 | Leetcode C语言题解之第32题最长有效括号

题目&#xff1a; 题解&#xff1a; int longestValidParentheses(char* s) {int n strlen(s);int left 0, right 0, maxlength 0;for (int i 0; i < n; i) {if (s[i] () {left;} else {right;}if (left right) {maxlength fmax(maxlength, 2 * right);} else if (…

Ubuntu20.4版本安装ROS教程

一、配置源 安装成功的Ubuntu系统自带的工具下载速度慢&#xff0c;不太好用&#xff0c;所以我们可以使用国内稳定高速且免费的镜像网站。 清华源&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple/ 阿里云&#xff1a;https://mirrors.aliyun.com/pypi/simple 中科大&…

使用Termux在Android设备上编译运行SpecCPU2006

Spec CPU 2006 的使用说明&#xff08;曲线救国版&#xff09; 因本部分实验用到的Spec CPU2006依赖于多个编译工具包&#xff0c;因此对源码的编译要在配置好环境的Linux设备上运行&#xff0c;根据实验发现&#xff0c;现有的环境&#xff08;包括adb和termux&#xff09;都不…

项目7-音乐播放器6+评论区

1.准备前端界面 前端小白&#xff1a;怎么为你的网页增加评论功能&#xff1f;&#xff08;一&#xff09;_为网页添加评论区怎么弄-CSDN博客 参考的上述文章的前端代码 我们从上述前端图片知道&#xff0c;我们数据库需要准备的字段&#xff1a; id,commentuserName,coomen…

✔ ★Java项目——设计一个消息队列(四)【整合数据库和文件、内存数据结构设计】

设计一个消息队列 ⼋. 整合数据库和⽂件上述代码中, 使⽤数据库存储了 Exchange, Queue, Binding, 使⽤⽂本⽂件存储了 Message.接下来我们把两个部分整合起来, 统⼀进⾏管理. 创建 DiskDataCenter封装 Exchange ⽅法封装 Queue ⽅法封装 Binding ⽅法封装 Message ⽅法 ⼩结九…

【CAD建模号】学习笔记(三):图形绘制区1

图形绘制区介绍 CAD建模号的图形绘制区可以绘制我们所需要的各种3D模型&#xff0c;绘制的图形即为模型对象&#xff0c;包括线、面、体等。 1. 二维图形绘制组 二维图形是建模的基础&#xff0c;大多数复杂的模型都是基于二维图形制作出来的&#xff0c;掌握二维图形的绘制等…

视频教程下载:用ChatGPT玩转海外抖音TikTok

CHATGPT for TikTok是一门前沿课程&#xff0c;旨在帮助您充分发挥TikTok广告活动的全部潜力。随着数字营销的爆炸性增长&#xff0c;企业需要使用先进的工具来保持竞争优势。在这门课程中&#xff0c;您将学习如何利用CHATGPT——一种先进的人工智能工具——来创建与目标受众产…

FMEA-MSR:监视及系统响应的补充FMEA——SunFMEA软件

FMEA-MSR与功能安全 FMEA-MSR的研究对象是软件系统、电子系统或机电系统&#xff0c;这些系统中包括至少一个传感器、一个控制单元和一个执行器&#xff0c;或它们的一个子集。分析有关在客户操作条件下的潜在失效&#xff0c;及对系统和车辆的影响后果。该方法考虑的是系统或…

以pytorch pipeline并行为例,分析各kernel的耗时占比及性能瓶颈

以pytorch pipeline并行为例,分析各kernel的耗时占比及性能瓶颈 1.生成pipeline并行的测试代码2.pipeline profing3.生成nsys2json.py代码4.将nsys sqlite格式转chrome json格式5.生成耗时成分统计代码6.统计耗时成分7.耗时成分如下:8.查看GPU PCIE链路状态9.链路状态如下10.Ns…

为什么选择气膜建造室内球馆?

在当今社会&#xff0c;越来越多的人选择使用气膜来建造室内球馆。这一选择背后有着多重原因和优势。 灵活性和便捷性 气膜结构球馆具有极高的灵活性和便捷性。相较于传统的建筑方式&#xff0c;搭建气膜球馆所需的时间更短&#xff0c;而且审批流程更为简单。尽管气膜球馆被视…

OpenHarmony多媒体-mp4parser

简介 一个读取、写入操作音视频文件编辑的工具。 编译运行 1、通过IDE工具下载依赖SDK&#xff0c;Tools->SDK Manager->Openharmony SDK 把native选项勾上下载&#xff0c;API版本>10 2、开发板选择RK3568&#xff0c;ROM下载地址. 选择开发板类型是rk3568&#xf…

Linux读写文件

前言 学习了文件系统&#xff0c;就能理解为什么说Linux下一切皆文件。 语言层面的操作 在c语言的学习中我们可以使用fopen()函数对文件进行操作。 int main() {//FILE * fp fopen("./log.txt", "w");//FILE * fp fopen("./log.txt", "…

C++入门之类和对象(中)

C入门之类和对象(中) 文章目录 C入门之类和对象(中)1. 类的6个默认对象2. 构造函数2.1 概念2.2 特性2.3 补丁 3. 析构函数3.1 概念3.2 特性3.3 总结 4. 拷贝构造函数4.1 概念4.2 特性4.3 总结 1. 类的6个默认对象 如果一个类中什么都没有&#xff0c;那么这个类就是一个空类。…

【每日刷题】Day7

【每日刷题】Day7 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 2. 203. 移除链表元素 - 力扣&#xff08;…

介绍与部署 Zabbix 监控系统

目录 前言 一、监控系统 1、主流的监控系统 2、监控系统功能 二、Zabbix 监控系统概述 1、Zabbix 概念 2、Zabbix 主要特点 3、Zabbix 主要功能 4、Zabbix 监控对象 5、Zabbix 主要程序 6、Zabbix 监控模式 7、Zabbix 运行机制 8、Zabbix 监控原理 9、Zabbix 主…