当前位置: 首页 > news >正文

LeetCode279:完全平方数,动态规划解法超过46%,作弊解法却超过97%

本篇概览

  • 这是道高频面试题,值得一看
  • 首先,这道题的难度是中等
  • 来看题目描述:
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 311 不是。
  • 示例1:
输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4
  • 示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9
  • 提示:
1 <= n <= 104

解题思路

  • 该题的解题思路是动态规划,核心解法有两点:
  1. 数字i,可能是某个数字的平方,例如数字9是数字3的平方
  2. 数字i,如果不是某个数字的平方,该数字能用此表达式表达:i = i - j*j + j*j
  • 对于上述第二种情况,就是动态规划状态转移方程的核心啦!
  • 假设dp[i]的定义是数字i的完全平方数的最少数量,那么表达式i = i - j*j + j*j就很容易用来分析dp[i]了
    在这里插入图片描述
  • 简单地说,就是:dp[i] = dp[i-j*j] + 1
  • 当然了,上述只是最基本的推测,不代表已经解完了,还剩一个重点:j到底是几?
  • 以10为例,10=(10-3*3) + 3*3,但是这不是唯一,还有10=(10-2*2) + 2*2,所以到底j等于几?根据题意,应该是dp[10-3*3]和dp[10-2*2]中最小的那个
  • 至此,分析完毕,可以愉快的写代码了

编码

  • 完整源码如下所示,可见,对应前面分析的j的多种可能,要取最小值
class Solution {
    public int numSquares(int n) {
        // i = i-j*j + j*j  - 注意这个j*j,就是完全平方数中的一个

        // dp[i]定义:数字i的完全平方数
        int[] dp = new int[n+1];

        dp[0] = 1;

        for (int i=1;i<=n;i++) {
            dp[i] = Integer.MAX_VALUE;

            for(int j=1;j*j<=i;j++) {
                // 如果出现i等于某个数字的平方,那么i的完全平方数就是1
                if (j*j==i) {
                    dp[i] = 1;
                    break;
                }

                // +1的意思就是j*j表示完全平方数中的一个
                dp[i] = Math.min(dp[i-j*j]+1, dp[i]);
            }
        }

        return dp[n];
    }
}
  • 编码完成后提交,顺利AC,只是成绩很不理想,仅超过45%,如下图
    在这里插入图片描述

反思,为啥成绩这么差?

  • 这么简单的动态规划操作,为何成绩这么落后?
  • 于是,我想到了一种可能:说不定可以作弊…
  • 理由有二
  1. 首先,这道题的输入是个数字,输出也是个数字,那就存在提前算好的可能,然后按输入返回提前算好的记过
  2. 其次,也是最关键的,就是题目要求中的那句提示,如下图,n小于等于一万,所以,我只要存一万个数字的对应关系,就行了呗:
    在这里插入图片描述
  • 看到这里,聪明的您应该知道我要如何作弊了,没错,就是把每个数字的完全平方数算出来,改动如下图
    在这里插入图片描述
  • 然后,运行上述代码,入参是10000,即可在控制台得到一个字符串,那就是从0到10000,每个数字的完全平方数
  • 接下来的要做的就很简单了,如下所示,用上述字符串做成一个int数组array,然后numSquares方法中就一行代码,返回入参n对应的完全平方数就行了
class Solution {
	// 数组的值就是刚才打印出来的字符串,太长了,就不完全贴出来了
    private int[] array = new int [] {1,1,2,3,1,2,3,4,2,1...};
    public int numSquares(int n) {
        return array[n];
    }
}
  • 至此,就一行代码了,相信成绩不会差了吧,运行一下试试,如下图,大跌眼镜了,一行代码也要45ms,从之前的超过45%跌落到超过22%

在这里插入图片描述

  • 突如其来的丢脸…
    在这里插入图片描述
  • 好吧,让我对着这一行代码捋捋,代码太少了,很容易捋清楚,如下图
    在这里插入图片描述
  • 找到了问题,改起来也就很容易了,如下图黄框所示,这一下,array数组在编译成class文件的时候被丢进了常量区,每次创建Solution实例的时候,不会再去创建array对象了
    在这里插入图片描述
  • 再次提交,这一回,作弊成功,用时和内存消耗双双超过百分之九十七
    在这里插入图片描述
  • 总的来说,动态规划是正解,如果条件允许,也能用歪门邪道作弊试试,可以开阔思路,同时取得好成绩,令人身心愉悦

相关文章:

  • docker安装以及运行nacos、rabbitmq、MySQL容器小记
  • S7-200SMART PLC进行MODBUS通信轮询时掉站处理和错误信息提取的具体方法演示
  • Transformer - Attention Is All You Need - 跟李沐学AI
  • c语言qsort函数使用教程
  • Android修行手册 - TabLayout全解析(下)-监听和示例
  • Java面试高频面试题总结
  • 手把手教你电机FOC控制【一】
  • 【Java面向对象】封装的认识与实现
  • 分布式限流不会用?一个注解简单搞定
  • Linux系统运维排故思路参考手册
  • 华为OD机考:0030-0031-n*n数组中二进制的最大数、整数的连续自然数之和
  • Jmeter的应用
  • 软件流程和管理(八):Ethics
  • SkyWalking持久化追踪数据
  • 数据导入与预处理-第4章-pandas数据获取
  • 【Leetcode】104. 二叉树的最大深度
  • Angular 4.x 动态创建组件
  • Date型的使用
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • JAVA并发编程--1.基础概念
  • JWT究竟是什么呢?
  • MQ框架的比较
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • SpriteKit 技巧之添加背景图片
  • 编写符合Python风格的对象
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 构造函数(constructor)与原型链(prototype)关系
  • 坑!为什么View.startAnimation不起作用?
  • 排序算法之--选择排序
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • # 利刃出鞘_Tomcat 核心原理解析(八)-- Tomcat 集群
  • (1)svelte 教程:hello world
  • (20050108)又读《平凡的世界》
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (javaweb)Http协议
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (苍穹外卖)day03菜品管理
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (四) Graphivz 颜色选择
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (译)计算距离、方位和更多经纬度之间的点
  • (原)本想说脏话,奈何已放下
  • (转)C#调用WebService 基础
  • (转)visual stdio 书签功能介绍
  • *p++,*(p++),*++p,(*p)++区别?
  • .gitignore不生效的解决方案
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET4.0并行计算技术基础(1)
  • .netcore如何运行环境安装到Linux服务器
  • .Net接口调试与案例
  • .NET框架设计—常被忽视的C#设计技巧
  • .net通用权限框架B/S (三)--MODEL层(2)
  • .NET中分布式服务