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

        这是楼主第一次不靠题解,挑战动态规划的中等题目,虽然最终结果只超过了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-1while(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.mzph.cn/pingmian/437.shtml

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

相关文章

基于1-wire总线的多路温度监测系统

前言 在现代工业生产和环境监测中&#xff0c;温度是一个关键的参数&#xff0c;它直接影响到生产过程的稳定性和产品质量。为了确保温度控制在安全和有效的范围内&#xff0c;需要一种可靠且高效的多路温度监测系统。随着微电子技术和传感器技术的发展&#xff0c;基于1-Wire…

Redis key(BigKey、MoreKey)的存储策略

1. MoreKey 案例 1.1 大批量往 redis 里面 插入2000w 测试数据key (1) Linux Bash 下面执行&#xff0c;插入 100w rootspray:~# for((i1;i<100*10000;i)); do echo "set k$i v$i" >> /tmp/redisTest.txt; done; 查看 rootspray:~# more /tmp/redisTest.…

elementui单个输入框回车刷新整个页面

<!-- 搜索 --> <el-form :model"queryParams" ref"queryForm" :inline"true"><el-form-item label"名称" prop"nameLike"><el-input v-model"queryParams.nameLike" placeholder"请输入…

Arcgis Pro2.5安装教程(内含安装文件)

​最近处理的数据量大&#xff0c;发现arcmap这种老产品属实是不行了&#xff0c;相比于下一代的Arcgis Pro,不但运行速度慢&#xff0c;也容易遇到突然关闭的问题&#xff0c;之前基于团队的选择也没办法&#xff0c;最近实在是被数据搞得无语了&#xff0c;一鼓作气装上了Arc…

319_C++_使用QT自定义的对话框,既能选择文件也能选择文件夹,为什么使用QListView和QTreeView来达成目的?

解析 1: 在 Qt 中,QFileDialog::setOption 方法用于设置文件对话框的一些选项,以改变其行为或外观。QFileDialog::DontUseNativeDialog 是这些选项之一,当设置为 true 时,它会告诉 QFileDialog 不要使用操作系统提供的原生文件对话框,而是使用 Qt 自己实现的对话框样式。…

WAF攻防-漏洞发现协议代理池GobyAwvsXray

知识点 1、Http/s&Sock5协议 2、Awvs&Xray&Goby代理 3、Proxifier进程代理使用 4、Safedog&BT&Aliyun防护在漏洞发现中&#xff0c;WAF会对三个方向进行过滤拦截&#xff1a; 1、速度频率问题&#xff08;代理池解决&#xff09; 2、工具的指纹被识别&am…

MySQL查询重复数据获取最新数据

方法一&#xff1a; 1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘se_jck的博客-CSDN博客 这个错误是由于 MySQL 的新版本中默认开启了ONLY_FULL_GROUP_BY模式&#xff0c;即在 GROUP BY 语句中的 SELECT 列表中&…

UE5不打包启用像素流 ubuntu22.04

首先查找引擎中像素流的位置&#xff1a; zkzk-ubuntu2023:/media/zk/Data/Linux_Unreal_Engine_5.3.2$ sudo find ./ -name get_ps_servers.sh [sudo] zk 的密码&#xff1a; ./Engine/Plugins/Media/PixelStreaming/Resources/WebServers/get_ps_servers.sh然后在指定路径中…

标准版配置的新增和使用

很多用户在使用标准版进行二开的时候&#xff0c;都会遇见需要增加配置的问题 这篇文章就详细的介绍了&#xff0c;怎么增加配置以及配置的调用 一、增加配置 1. 增加配置分类 在菜单维护-开发配置-配置分类中&#xff0c;点击添加配置分类 父级分类&#xff1a;选择此分类的…

基于51单片机电子钟闹钟12/24小时制LCD显示( proteus仿真+程序+设计报告+讲解视频)

基于51单片机电子钟闹钟12/24小时制LCD显示 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真设计4. 程序代码5. 设计报告6. 设计资料内容清单&&下载链接 基于51单片机电子钟闹钟12/24小时制LCD显示( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteu…

如何自动监控WordPress网站的运行状态

近来有不少Hostease的客户来咨询关于监控网站在线情况的方法&#xff0c;确实&#xff0c;尽管我们采取了各方面的措施来维护和保护WordPress网站&#xff0c;网站依然有可能由于一些不可控的原因关闭&#xff0c;这种情况往往事发突然&#xff0c;如果没有提前做好准备&#x…

评分卡制作过程中关键参数设定的思考

评分卡制作过程中关键参数设定的思考 评分卡、列线图和网络APP都是预测模型进入生产场景的形式。评分卡&#xff0c;常用于银行或金融机构的贷款审批过程中。其原理在于通过一系列与借款人相关的因素&#xff08;如年龄、收入、职业、信用记录等&#xff09;来为每个人打分&am…

一文速览Llama3:含8B和70B、长度8K、15T训练数据、组合PPO和DPO等方法

前言 4.19日凌晨正准备睡觉时&#xff0c;突然审稿项目组的文弱同学说&#xff1a;Meta发布Llama 3系列大语言模型了 一查&#xff0c;还真是 本文以大模型开发者的视角&#xff0c;帮你迅速梳理下LLama的关键特征&#xff0c;并对比上一个版本的LLama2&#xff0c;且本文后…

Python 字符串 Base64

因消息传输的需要&#xff0c;我们需要对大量文本的字符串进行一下 Base64 转换。 这样的好处是因为在传输的字符串中可能有存在一些特殊字符&#xff0c;这些特殊在经过网络传输的时候会出现编码的问题&#xff0c;并且会影响传输稳定性。 使用 Base64 可以避免这个问题。 方…

面试遇到的算法题

1.字符串转换整数 读入字符串并丢弃无用的前导空格检查下一个字符&#xff08;假设还未到字符末尾&#xff09;为正还是负号&#xff0c;读取该字符&#xff08;如果有&#xff09;。 确定最终结果是负数还是正数。 如果两者都不存在&#xff0c;则假定结果为正。读入下一个字…

GitOps 和 DevOps 有什么区别?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

03 JavaScript学习:浏览器中执行 JavaScript

我比较习惯Chrome浏览器。 Chrome 是由 Google 开发的免费网页浏览器&#xff0c;调试代码非常方便。 Chrome 官网地址&#xff1a;https://www.google.com/intl/zh-CN/chrome/。 控制台输出 浏览器的控制台是开发者工具中的一个重要组成部分&#xff0c;它可以用来查看网页…

【氮化镓】GaN HEMT失效物理和可靠性

概述: 本文是一篇关于AlGaN/GaN基高电子迁移率晶体管(HEMTs)的失效物理和可靠性研究的综述文章,发表在2013年10月的《IEEE Transactions on Electron Devices》上。文章由Enrico Zanoni等人撰写,主要关注了影响栅极边缘和肖特基结的失效机制,并探讨了提高这些器件可靠性…

springboot的开发流程

文章目录 springboot的开发流程 1.创建maven项目2.引用依赖 1&#xff09;起步依赖2&#xff09;项目依赖3.启动类4.配置文件5.业务代码 1)dto2)controller6.restful测试7.部署 1&#xff09;打包2&#xff09;部署 springboot的开发流程 1.创建maven项目 新建maven项目 配置…

若依框架后台管理系统_修改后台管理密码

若依框架后台管理系统_修改后台管理密码 1. 找见加密函数&#xff1a; /*** 生成BCryptPasswordEncoder密码** param password 密码* return 加密字符串*/public static String encryptPassword(String password){BCryptPasswordEncoder passwordEncoder new BCryptPasswordE…