[ map集合、循环链表 ] 202.快乐数

199 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情

每日刷题 2021.04.26

  • leetcode原题链接:
  • 难度:简单
  • 方法:map集合、循环链表

题目

  • 编写一个算法来判断一个数 n 是不是快乐数。
  • 「快乐数」 定义为:
    • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
    • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
    • 如果这个过程 结果为 1,那么这个数就是快乐数。
    • 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例

  • 示例1
输入: n = 19
输出: true
解释: 12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
  • 示例2
输入: n = 2
输出: false

提示

  • 1 <= n <= 231 - 1

解题思路

  • 仔细读题,看题目中加粗的字体。其实就已经告诉了我们有两种情况:
    • 1.数循环变为1
    • 2.数无限循环
  • 需要模拟题目中将当前的数n逐位分开后,对其平方后,再加和起来。可以看到我们只需要写好一次的操作,后面的操作,可以通过不断的重复这段操作来实现。
    • 临界条件:n / 10 == 0的时候,表示所有的位数都已经处理过了。
    • 一次的逻辑:(获取)取余10,得到最后一位的数值,(处理)将其平方;再(获取)将当前的数/ 10,丢掉已经处理过的最后一位数值,得到下一轮的开始值。

map集合

  • 因为有可能会存在循环,因此可以将已经得到的数值,存储在map集合中,如果下一次计算的结果,已经在map集合中,那么就说明,进入了循环,直接返回false
  • 与之而来的问题:如果数值很多很大的时候,map集合不足以存储这些所有的数值,那么如何优化呢?

循环链表

  • 分析本题可知,有一种情况可能会无限循环,那么就可以将题转换成:判断链表有环还是无环。
    • 有环 => false
    • 无环 => true
  • 判断链表中是否存在环的经典做法,就是使用快慢指针。记慢指针last,快指针fast。如果链表中存在环,那么快指针一定会和慢指针相遇;如果无环,则快指针先到达终点。
  • 适用到本题上,就是简化掉链表的数据结构,单纯的去判断fastlast指向的数值,是否有重复的,如果相等,则存在无限循环。
  • 因此总结两种情况:
    • 当快慢指针所代表的值相同时,直接返回false
    • 当快指针等于1的时候,跳出循环,返回true
  • 注意⚠️:需要特别注意,如果你一开始赋值的时候,将快慢指针初始化为一样的值,那么就需要在执行完第一次之后,再判断last和fast是否相等。

AC代码

循环链表

var isHappy = function(n) {
  // 快乐就完事了
  // 通过题目所给的分析可知:循环可以使用循环链表来进行判断
  // 三种情况: 变为1 / 无限循环 / 无穷大
  // 检测循环链表的方法:快慢指针
  // 如果存在环,那么快慢指针就会相遇
  let getNext = function (n) {
    return n.toString().split('').map(i => i ** 2).reduce((a, b) => a + b);
  }
  let slow = n,fast = n,flag = false;
  while(fast != 1) {
    if(slow == fast && flag) return false;
    flag = true;
    slow = getNext(slow);
    fast = getNext(getNext(fast));
  }
  return true;
};

总结

  • 读题还需要再认真一些,多注意加粗的字体表示的含义,读好题,思路想清楚,再敲代码。