面试经典150题——快乐数

​"Success is not final, failure is not fatal: It is the courage to continue that counts." - Winston Churchill

person sitting inside restaurant

1. 题目描述

image-20240223175144069

2.  题目分析与解析

2.1 思路一

还是最简单的,模拟最直观的思路,就是进行一个while循环。比如:

image-20240223182627567

根据上面的示例,可以知道while循环终止条件为各个位上的平方和为1,就可以返回true。但是对于false的情况怎么办呢?

此时就需要注意题目中提到的

image-20240223183905806

它为什么把无限循环加粗?那就是在向你透露一个信息,对于无限循环的情况那就是需要返回false的情况。

所以我们现在的目的就是找到无限循环到底是什么样的。需要找到这个无限循环的规律,那我们就得找一些出现无限循环的数来看看,也就是找到那些返回false的情况。看看题目中的测试用例:

image-20240223184225104

这不是就有一个?因此我们就可以以 2 作为突破口,看看究竟无限循环是什么意思。

image-20240223184820349

上面是以2为用例的一次次计算,发现什么了吗?

image-20240223185042756

有没有发现开始循环了?所以遇见问题不要慌,把能用的信息都用上多试一试就能解决了。

既然发现有循环了,那是不是就很好办了,我们就可以使用一个结构,存储那些循环的部分,如果在后续while过程中发现开始和循环的部分重复了,就可以判断该数不是快乐数了。

存储那些循环的部分,到底是哪部分?

既然要循环,继续看这个图:

image-20240223185514987

两个红色部分有没有看出点什么?2和20,两个就多了几个0,因此我们就可以假设出现循环的位置就是我们的当前位置的值可能加了几个0,这样才能使得他们生成的下一个数字一样。于时我根据这个思路写了代码,但是很遗憾在测试用例为3时:

image-20240223192959075

所以我又根据3作为输入,重新计算每一次的值:

image-20240223193038909

这我发现又冒出来了4这个数字,又开始循环了。直到这时我才知道原来这个数字就是出现循环返回false的条件,也就是说对于那些不是快乐数的n,它肯定会走到4开头的循环。

而我之前运行超时的假设是:

image-20240224073257877

对于任何数,如果不是快乐数,那么就会有一个轮次的固定数,也就是如上图红色一个轮次,蓝色一个轮次,这两轮除了第一个数字不一样以外其它部分全部相同,所以我在之前的代码中就去判断第1次while循环的结果和某一次是否相同,当出现相同值就说明进入了第二轮次循环,就可以返回false。所以我假设错误的结构是这样的:

image-20240224074501912

但是实际上是所有的非快乐数都会进入一个循环:4→16→37→58→89→145→42→20→4,也就是实际的结构是如下图:

fig2

现在规律找到了,那么我们就可以缕一缕代码思路了。

代码思路:

  1. 定义一个hashMap,存储平方值

  2. 进行while循环计算每一个sum,并将计算结果在最后赋值给n

  3. 当发现n等于1时,说明满足条件,返回true

  4. 当发现n等于4时,说明进入循环,返回false

总结

遇见问题多尝试,多试一试就能发现规律。开始我也没头绪,但是试着试着就找到规律了,所以还是得多动手。

2.2 思路二——判断是否循环

在这里再讲一下快慢指针法,因为我们已经知道如果某个数字不是快乐数,就肯定会出现循环,因此我们就需要判断是否有循环即可,至于这个循环是什么循环,我们并不关心。而什么是循环,循环就是当前节点连到下一个点,这样一直连下去最后还能回到当前节点,那么是不是就是一个环状结构。

因此判断一个数是不是快乐数就是判断它形成的数字链中是否有环,就是检测一个链表是否有环。这个问题怎么解决呢?

在给答案之前先来思考一下,如何判断是否会进入环?

2.2.1 思路二——1

我们是不是可以用一个定义一个hashMap,保存走过的值,如果发现某一个值开始在之前的hashMap中包含了,那么肯定下一个数字也被包含,因为相同数字的下一个数字肯定还一样。因此只要发现某一个值开始在之前的hashMap中包含了,就说明有循环。

代码思路:

  1. 定义一个hashMap,保存走过的值,定义一个hashMap,存储平方值(只为了做加速运算的作用)

  2. 进行循环,条件为如果n等于1,表示成功,那么结束循环

    • 将n存入走过的hashMap

    • 计算新的值

    • 判断之前走过的值中是否有当前的新值,如果有说明进入循环了,就需要返回false

    • 将新值赋值给 n

2.2.2 思路二——2

除了上述思路以外,还有一种方式就是假想一下两个人现在准备去操场跑步,他们准备一直在操场跑不停止。

下载

假设他们都从宿舍出发,A 8点就到了跑道开始跑步,B 10点才到跑道跑步,并且我们假设A 的速度是5m/s,B的速度是3m/s,那么A和B会相遇嘛?

答案显而易见即使他们不同时到达,而且速度不一样,但是他们肯定会相遇。那如果A的速度是100m/s,B的速度是1m/s呢?

答案还是会相遇,这是显而易见的,因为他们的速度虽然不同,但是速度差就决定了他们彼此相互靠近的速度。

因此把这种思想套用在我们的题目上,我们要判定是否出现环状结构,那么是不是就可以让两个速度不一样的人用不同的时间从宿舍去操场,开始跑步。

  • 如果这个数不是快乐数,它就不会出现循环结构,也就是说他们的跑道会变成直线跑道不是快乐数那就肯定有终点,这个终点就是出现1的情况,那么他们之间的距离肯定会不断拉大,并且跑的快的人肯定比跑的慢的人先到达终点。

images

  • 如果这个数是快乐数,那么它就会出现环状结构,就是有循环,那么他们就是围绕环形跑道进行奔跑:

那他们肯定会在某一个地方相遇,这就是终止条件。

其实上述思路就是 弗洛伊德循环查找算法

所以对于是快乐数和不是快乐数,两个不同速度的跑步者都能找到终止条件,那么程序不也一样?所以根据以上思路,我们可以写出如下代码思路。

代码思路:

  1. 假定两个速度不同的跑步者,这里的速度其实就是遍历节点的个数,假设A每次遍历两个,B每次遍历一个。那么A和B要么相遇,要么A先走到1。

  2. 定义一个hashMap,存储平方值(加速运算)

  3. while循环计算每一次的结果,终止条件为速度快的是否到达终点 1 ,或者两个跑步者是否相遇

    • 计算A跑步者每次跑步后的位置

    • 计算B跑步者每次跑步后的位置

3. 代码实现

3.1 思路一

image-20240223194011359

image-20240223193837397

3.2 思路二

3.2.1 思路二——1

image-20240224085925867

image-20240224085901306

3.2.1 思路二——2

image-20240224085840396

image-20240224085816702

4. 相关复杂度分析

4.1 思路一

时间复杂度
  1. 初始化HashMap: 初始化操作的时间复杂度为O(1),因为这里只有10个固定的映射关系被添加到HashMap中,与输入大小n无关。

  2. while循环: 这个循环的次数取决于n减小到1或者进入循环(如开始重复相同的数值)所需的迭代次数。对于快乐数问题,已知所有非快乐数最终都会进入到4, 16, 37, 58, 89, 145, 42, 20, 4的循环中。因此,循环的次数是有上限的,但是这个上限如何精确定义对于任意的n来说是不明确的。尽管如此,我们可以认为这个上限存在,从而可以认为该循环的时间复杂度是O(log n),因为每一次迭代n都会显著减小(至少在多数情况下)。

  3. 内部while循环: 这个循环用于计算n的每一位数的平方和。对于一个k位数字,这个循环将执行k次。因为k = log10(n),所以这个循环的时间复杂度是O(log n)

因此,总的时间复杂度可以被视为O(log n * log n),因为外部循环和内部循环的复杂度都是O(log n),并且它们是嵌套的。

空间复杂度
  1. HashMap: 因为HashMap中存储了10个固定的键值对,所以它的空间复杂度是O(1)

  2. 临时变量: sum和循环中的其他临时变量占用的空间是常数级别的,因此它们的空间复杂度也是O(1)

所以该函数空间复杂度是O(1),因为所需的额外空间不随输入n的大小变化而变化。

4.2 思路二

方法一分析 (isHappy2)
  • 时间复杂度:

    • 初始化squareMap的时间复杂度为O(1),因为它仅包含0到9的平方,是一个常数时间操作。

    • 主循环中,对于每个n,我们计算其数字平方和,直到n变为1或进入循环。这个过程的时间复杂度取决于n的大小和它进入循环的快慢。在最坏的情况下,这可能接近O(log n)到O(log^2 n),因为每次迭代都会减少n的大小,但是具体取决于数字的分布和循环的检测。

    • 使用numMap来检查循环的存在,每次插入和查找操作的时间复杂度为O(1)。

  • 空间复杂度:

    • squareMap的空间复杂度为O(1)。

    • numMap的空间复杂度最坏情况下为O(log n)到O(log^2 n),因为它存储了遍历过程中的每个数字,直到找到循环或达到1。

方法二分析 (isHappy3)
  • 时间复杂度:

    • 初始化squareMap与方法一相同,时间复杂度为O(1)。

    • 使用快慢指针的方法,时间复杂度主要依赖于找到循环或1所需的步数。快慢指针技巧通常用于检测链表中的循环,其效率高于简单的追踪方法,因为它减少了不必要的迭代。对于快乐数问题,这种方法能够更快地到达重复序列或结束,因此在实践中,它的时间效率通常比线性检查所有元素要好,但最坏情况下的理论时间复杂度仍然是O(log n)到O(log^2 n)。

  • 空间复杂度:

    • squareMap的空间复杂度为O(1)。

    • 与方法一不同,方法二没有使用额外的哈希映射来存储遍历过的数字,因此它的空间复杂度优于方法一,主要是O(1),因为除了几个变量之外没有存储大量数据。

总结
  • 方法一(isHappy2)的时间复杂度大约是O(log n)到O(log^2 n),空间复杂度是O(log n)到O(log^2 n)。

  • 方法二(isHappy3)的时间复杂度同样是O(log n)到O(log^2 n),但空间复杂度降低到O(1)。

方法二在空间效率上有显著优势,因为它避免了存储所有遍历过的数字。在时间效率方面,两种方法可能相似,但方法二通常更优,因为快慢指针技巧能更快地发现循环或达到1。

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

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

相关文章

yolov8-seg dnn调用

接上篇一直更换torch、opencv版本都无法解决这个问题(seg调用dnn报错)。那问题会不会出在yolov8源码本身呢。yolov8的讨论区基本都看过了,我决定尝试在其前身yolov5的讨论区上找找我不信没人遇到这个问题。很快找到下面的讨论第一个帖子&…

20个改善编码的Python异常处理技巧,让你的代码更高效

异常处理是写好代码的一个重要的方面,虽然许多开发人员都熟悉基本的try-except块,但是有很多更深入的知识可以使异常处理更高效、更可读和更python化。所以本文将介绍关于Python异常的20个可以显著改善编码的Python异常处理技巧,这些技巧可以…

软件性能测试和功能测试有何联系和区别?第三方软件检测机构简析

软件性能测试和功能测试是软件开发过程中非常重要的两个环节。从根本上说,它们都是为了保证软件质量和可靠性,但它们的目标和方法却有所不同。 软件性能测试是评估软件在特定负载下的性能表现,包括响应时间、吞吐量、并发能力等指标。它通过…

Jenkins详解

目录 一、Jenkins CI/CD 1、 Jenkins CI/CD 流程图 2、介绍 Jenkins 1、Jenkins概念 2、Jenkins目的 3、特性 4、产品发布流程 3、安装Jenkins 1、安装JDK 2、安装tomcat 3.安装maven 4安装jenkins 5.启动tomcat,并页面访问 5.添加节点 一、Jenkins CI/…

Opencv实战(2)绘图与图像操作

Opencv实战(2)绘图与图像操作 指路前文:Opencv实战(1)读取与像素操作 三、基本绘图 文章目录 Opencv实战(2)绘图与图像操作三、基本绘图(1).line(2).rectangle(3).circle 四、图像处理(1).颜色空间1.意义2.cvtColor()3.inRange()4.适应光线 (2).形态操作1.腐蚀2.膨…

Python语句(一)【条件语句】

条件语句:通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。 其程序流程图如下: 条件语句包括:if 判断条件:执行语句…… else:执行语句……orif 判断条件1:执行语句1…… el…

电商+支付双系统项目------项目部署到服务器

我已经把这个项目的所有模块都做好了。那么,现在我们要做的就是将这个项目部署发布了。其实关于部署发布网上有很多的文章都会教,我就不写哪些很具体的步骤了,我就简单的总结一下怎么部署这个项目,让大家对项目部署有一个整体的认…

kubernetes的网络flannel与caclio

flannel网络 跨主机通信的一个解决方案是Flannel,由CoreOS推出,支持3种实现:UDP、VXLAN、host-gw udp模式:使用设备flannel.0进行封包解包,不是内核原生支持,上下文切换较大,性能非常差 vxlan模…

瑞_23种设计模式_装饰者模式

文章目录 1 装饰者模式(Decorator Pattern)1.1 介绍1.2 概述1.3 装饰者模式的结构 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析5 总结5.1 装饰者模式的优缺点5.2 装饰者模式的使用场景5.3 装饰者模式 VS 代理模式 &#x…

dpdk环境搭建和工作原理

文章目录 1、DPDK环境搭建1.1、环境搭建1.2、编译DPDK 2、DPDK工作原理 1、DPDK环境搭建 1.1、环境搭建 工具准备:VMware、ubuntu16.04。 (1)VMware添加两个网卡。桥接网卡作为 DPDK 运行的网卡,NAT 网卡作为 ssh 连接的网卡。 …

【动态规划】【前缀和】【推荐】2463. 最小移动总距离

作者推荐 【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子 本文涉及知识点 动态规划汇总 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 2463. 最小移动总距离 X 轴上有一些机器人和工厂。给你一个整数数组 robot &#xff0c…

【统计分析数学模型】判别分析(四):机器学习分类算法

【统计分析数学模型】判别分析(四):机器学习分类算法 一、机器学习分类算法1. 交叉验证方法2. 案例数据集3. 数据标准化 二、决策树模型1. 基本原理2. 计算步骤3. R语言实现 三、K最邻近分类1. 基本原理2. K值的选择3. R语言实现 四、支持向量…

5分钟JavaScript快速入门

目录 一.JavaScript基础语法 二.JavaScript的引入方式 三.JavaScript中的数组 四.BOM对象集合 五.DOM对象集合 六.事件监听 使用addEventListener()方法添加事件监听器 使用onX属性直接指定事件处理函数 使用removeEventListener()方法移除事件监听器 一.JavaScript基础…

投屏软件Airserver优惠码来了,使用能减10元(有图有真相)

Airserver是一款非常实用的手机投屏到电脑软件。AirServer for Mac是一款能够通过本地网络将音频、照片、视频以及支持AIrPlay功能的第三方App,从 iOS 设备无线传送到 Mac 电脑的屏幕上,把Mac变成一个AirPlay终端的实用工具。 Airserver中文官网地址&…

【算法与数据结构】回溯算法、贪心算法、动态规划、图论(笔记三)

文章目录 七、回溯算法八、贪心算法九、动态规划9.1 背包问题9.2 01背包9.3 完全背包9.4 多重背包 十、图论10.1 深度优先搜索10.2 广度优先搜索10.3 并查集 最近博主学习了算法与数据结构的一些视频,在这个文章做一些笔记和心得,本篇文章就写了一些基础…

【C++】类和对象---友元,内部类,匿名对象详解

目录 友元 友元函数 友元类 内部类 匿名对象 ⭐友元 友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以 友元不宜多用。 友元分为:友元函数和友元类。 ⚡友元函数 先看一个问题&#x…

使用 yarn 的时候,遇到 Error [ERR_REQUIRE_ESM]: require() of ES Module 怎么解决?

晚上回到家,我打开自己的项目,执行: cd HexoPress git pull --rebase yarn install yarn dev拉取在公司 push 的代码,然后更新依赖,最后开始今晚的开发时候,意外发生了,竟然报错了,…

Python流程控制有知道的吗?

流程控制是编程的核心概念之一,Python也不例外。在Python中,程序的流程控制结构主要包括顺序结构、选择结构和循环结构。这些结构让程序员能够更好地组织代码,使其按照特定的逻辑执行。 1.顺序结构 顺序结构是Python中最简单的流程控制结构&…

Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】

有的自定义系统,对于自己外接的USB摄像头,android原生的camera和camera2都无法打开,CameraX也用不了。这时候就要用libusbCamera,这个库可以打开摄像头,还可以多摄像头同时预览。本文主要是同时打开3个USB摄像头的项目…

Spring Boot应用集成Actuator组件以后怎么自定义端点暴露信息

一、 前言 在平时业务开发中,我们往往会在spring Boot项目中集成Actuator组件进行系统监控,虽然Actuator组件暴露的端点信息已经足够丰富了,但是特殊场景下,我们也需要自己暴露端点信息,此时应该怎么操作呢&#xff1…