Leetcode 202题 快乐数:数字世界中的奇妙旅程

Leetcode 202题 快乐数:数字世界中的奇妙旅程

Leetcode 202题 快乐数:数字世界中的奇妙旅程

视频地址

因为想更好的为大佬服务,制作了同步视频,这是Bilibili的视频地址

在数学的奇妙花园里,有一种特殊的数字被赋予了"快乐"的称号。快乐数(Happy Number)就像一位在数字迷宫中寻找出口的旅人,它遵循着特定的变换规则,一步步走向最终的归宿——1。

快乐数的定义:对于一个正整数,如果将其各位数字的平方和不断进行替换,最终能够得到1,那么这个数就被称为快乐数。反之,如果陷入一个不包含1的循环,那么这个数就是不快乐的。

让我们以19为例,展开这段数字的奇妙旅程:

19 → 1² + 9² = 82 82 → 8² + 2² = 68 68 → 6² + 8² = 100 100 → 1² + 0² + 0² = 1 

瞧!经过4步变换,19最终到达了幸福的终点——1,因此它是一个快乐数。

解题思路:从数字到链表的思维转换

链表思维的巧妙应用

虽然表面上我们处理的是数字,但如果我们把每个数字看作链表中的一个节点,把数字变换规则看作指向下一个节点的指针,那么快乐数问题就转化为了链表判环问题

19

82

68

100

1

null

图1:快乐数的链表表示法。快乐数最终会指向1,然后结束;不快乐的数则会进入一个循环

快慢指针:龟兔赛跑的智慧

在链表判环问题中,快慢指针算法是一种经典且高效的解决方案。我们可以让两个指针以不同的速度遍历这个"数字链表":

  • 慢指针(p):每次计算一次数字变换
  • 快指针(q):每次计算两次数字变换

如果存在环(即数字不快乐),快慢指针终将相遇;如果数字快乐,快指针会率先到达1。

算法实现:C++代码解析

关键函数:数字变换

// 计算数字n的下一个变换结果intgetNext(int n){int sum =0;while(n >0){int digit = n %10;// 获取最后一位数字 sum += digit * digit; n /=10;// 去掉最后一位数字}return sum;}

快乐数判断主逻辑

boolisHappy(int n){int slow = n;// 慢指针int fast =getNext(n);// 快指针先走一步// 当快慢指针不相等且快指针未到达1时继续循环while(fast !=1&& slow != fast){ slow =getNext(slow);// 慢指针走一步 fast =getNext(getNext(fast));// 快指针走两步}return fast ==1;// 判断快指针是否到达1}

数学深度:数字会无限增大吗?

一个自然的疑问是:在变换过程中,数字会不会变得越来越大,最终无限增长?让我们通过数学分析来解答这个问题。

对于一个m位数n,其各位数字平方和的最大值为81m(当所有位都是9时)。而:

  • 当m=3时,最大和为243(3×81),远小于999
  • 当m=4时,最大和为324,远小于9999

事实上,对于任何大于3位的数字,经过一次变换后数字都会变小。因此,数字不会无限增大,最终要么收敛到1,要么进入一个有限的循环。

快乐数的性质与统计

快乐数有一些有趣的性质:

  1. 所有不快乐数最终都会进入循环:4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4
  2. 1到100之间的快乐数有:
快乐数变换步骤
10
75
101
132
194

表1:部分快乐数及其到达1所需的步骤数

复杂度分析与优化

时间复杂度:O(log n),因为每次变换都会显著减少数字的大小(对于大数而言)。
空间复杂度:O(1),因为我们只使用了常数个额外空间。

扩展思考

  1. 快乐数的密度:随着数字增大,快乐数的比例会如何变化?
  2. 快乐素数:既是素数又是快乐数的数字,如7、13、19等。
  3. 连续快乐数:是否存在连续的快乐数?(例如31和32都是快乐数)

快乐数问题不仅是一个有趣的编程练习,更是数学之美的一个缩影。它展示了如何将看似简单的数字变换转化为深刻的算法问题,并通过巧妙的思维转换找到高效的解决方案。

Leetcode 202题 快乐数:数字世界中的奇妙旅程

Read more

【算法通关指南:算法基础篇】二分算法:1.在排序树组中查找元素的第一个和最后一个位置 2.牛可乐和魔法封印

【算法通关指南:算法基础篇】二分算法:1.在排序树组中查找元素的第一个和最后一个位置 2.牛可乐和魔法封印

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、二分算法 * 二、在排序树组中查找元素的第一个和最后一个位置 * 2.1题目 * 2.2 算法原理 * 2.3代码 * 三、牛可乐和魔法封印 * 3.1题目 * 3.2 算法原理 * 3.3代码 * 总结与每日励志 前言 本专栏聚焦算法题实战,系统讲解算法模块:以《c++编程》,《数据结构和算法》《基础算法》《算法实战》 等几个板块以题带点,讲解思路与代码实现,帮助大家快速提升代码能力ps:本章节题目分两部分,比较基础笔者只附上代码供大家参考,其他的笔者会附上自己的思考和讲解,希望和大家一起努力见证自己的算法成长 一、

By Ne0inhk
【笔试】算法的暴力美学——牛客 NC221681:dd爱框框

【笔试】算法的暴力美学——牛客 NC221681:dd爱框框

一、题目描述 二、算法原理 思路:滑动窗口 1)定义两个指针,一开始都为0,cur 从左开始遍历,定义一个 sum 来表示 prev 到 cur 的之间的值的总和,当 sum >= x 时,我们要根据题目条件来保存 prev 和 cur 的值; 2)当 sum >= x 时,我们记录完 prev 和 cur 的值的之后,sum -= arr[ prev ],prev++ ,往后走,只要满足条件 sum >= x 我们就要记录

By Ne0inhk
【优选算法】——二分查找!

【优选算法】——二分查找!

目录 1、二分查找 2、在排序数组中查找元素的第一个和最后一个位置 3、搜索插入位置 4、x的平方根 5、山脉数组的封顶索引 6、寻找峰值  7、寻找旋转排序数组中的最小值 8、点名 9、完结散花 1、二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1:输入:nums = [-1,0,3,5,9,12], target = 9 输出: 4

By Ne0inhk
排序算法指南:归并排序(非递归)

排序算法指南:归并排序(非递归)

前言:              非递归实现归并排序,通常被称为 “自底向上”(Bottom-Up) 的归并排序,与递归版本(先将数组对半拆分直到只剩一个元素,再通过递归栈回溯合并)不同,非递归版本直接从最小的子数组(长度为1)开始,两两合并,然后长度翻倍(2, 4, 8 ...),直到合并完整个数组。                                                                 一、归并排序非递归的核心思路          递归算法转换为非递归实现主要有两种常见方法:          1.使用栈结构模拟递归过程          2.将递归逻辑改写为循环结构          1.1 栈模拟失效          如果仅通过栈结构模拟递归过程,我们只能够做到拆分数组,而不能做到合并数组。          假设我们要排序数组 arr = [8, 4, 5, 7],下标是 0 到 3。          初始状态:栈中有任务 [0, 3]。                   第一步:弹

By Ne0inhk