其他分享
首页 > 其他分享> > 202. 快乐数

202. 快乐数

作者:互联网

202. 快乐数

题目:202.快乐数(简单)

题目描述

编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」定义为:

如果 n 是快乐数就返回 true ;不是,则返回 false 。

示例 1:

输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1

示例 2:

输入:n = 2
输出:false

提示:

题解

思路:寻找无线循环发生的情况,即循环将出现在每次计算的平方和当中,因此我们需要用一个容器来记录每一次的平方和。因为我们需要快速地判断当前的平方和是否已经存在容器中了,所以我们可以选择使用哈希算法。选取 unordered_set 比较合适。

代码:C++版本

bool isHappy(int n) {
   unordered_set<int> sums;
   if (n == 1) return true;
   while (n != 1){
       int sum = 0;
       while (n != 0) {
           int tmp = n % 10;
           sum += tmp*tmp;
           n = n / 10;
      }
       //快乐数
       if (sum == 1) return true;
       //没找到,插入
       else if (sums.find(sum) == sums.end()){
           sums.insert(sum);
      }
       //找到,结束循环
       else if (sums.find(sum) != sums.end()){
           break;
      }
       n = sum;
  }
   return false;
}

官方解法

官方解法

方法一:用哈希集合检测循环 我们可以先举几个例子。我们从 7 开始。则下一个数字是 49(因为 7^2=49),然后下一个数字是 97(因为 4^2+9^2=97)。我们可以不断重复该的过程,直到我们得到 1。因为我们得到了 1,我们知道 7 是一个快乐数,函数应该返回 true。

202_fig1

再举一个例子,让我们从 116 开始。通过反复通过平方和计算下一个数字,我们最终得到 58,再继续计算之后,我们又回到 58。由于我们回到了一个已经计算过的数字,可以知道有一个循环,因此不可能达到 1。所以对于 116,函数应该返回 false。

202_fig2

根据我们的探索,我们猜测会有以下三种可能。

对于 3 位数的数字,它不可能大于 243。这意味着它要么被困在 243 以下的循环内,要么跌到 1。4 位或 4 位以上的数字在每一步都会丢失一位,直到降到 3 位为止。所以我们知道,最坏的情况下,算法可能会在 243 以下的所有数字上循环,然后回到它已经到过的一个循环或者回到 1。但它不会无限期地进行下去,所以我们排除第三种选择。 即使在代码中你不需要处理第三种情况,你仍然需要理解为什么它永远不会发生,这样你就可以证明为什么你不处理它。

算法

算法分为两部分,我们需要设计和编写代码。

第 1 部分我们按照题目的要求做数位分离,求平方和。 第 2 部分可以使用哈希集合完成。每次生成链中的下一个数字时,我们都会检查它是否已经在哈希集合中。

我们使用哈希集合而不是向量、列表或数组的原因是因为我们反复检查其中是否存在某数字。检查数字是否在哈希集合中需要 O(1) 的时间,而对于其他数据结构,则需要 O(n) 的时间。选择正确的数据结构是解决这些问题的关键部分。

class Solution {
   private int getNext(int n) {
       int totalSum = 0;
       while (n > 0) {
           int d = n % 10;
           n = n / 10;
           totalSum += d * d;
      }
       return totalSum;
  }

   public boolean isHappy(int n) {
       Set<Integer> seen = new HashSet<>();
       while (n != 1 && !seen.contains(n)) {
           seen.add(n);
           n = getNext(n);
      }
       return n == 1;
  }
}

复杂度分析 确定这个问题的时间复杂度对于一个「简单」级别的问题来说是一个挑战。如果您对这些问题还不熟悉,可以尝试只计算 getNext(n) 函数的时间复杂度。

方法二:快慢指针法 通过反复调用 getNext(n) 得到的链是一个隐式的链表。隐式意味着我们没有实际的链表节点和指针,但数据仍然形成链表结构。起始数字是链表的头 “节点”,链中的所有其他数字都是节点。next 指针是通过调用 getNext(n) 函数获得。

意识到我们实际有个链表,那么这个问题就可以转换为检测一个链表是否有环。因此我们在这里可以使用弗洛伊德循环查找算法。这个算法是两个奔跑选手,一个跑的快,一个跑得慢。在龟兔赛跑的寓言中,跑的慢的称为 “乌龟”,跑得快的称为 “兔子”。

不管乌龟和兔子在循环中从哪里开始,它们最终都会相遇。这是因为兔子每走一步就向乌龟靠近一个节点(在它们的移动方向上)。

算法

我们不是只跟踪链表中的一个值,而是跟踪两个值,称为快跑者和慢跑者。在算法的每一步中,慢速在链表中前进 1 个节点,快跑者前进 2 个节点(对 getNext(n) 函数的嵌套调用)。 如果 n 是一个快乐数,即没有循环,那么快跑者最终会比慢跑者先到达数字 1。 如果 n 不是一个快乐的数字,那么最终快跑者和慢跑者将在同一个数字上相遇。

class Solution {

    public int getNext(int n) {
       int totalSum = 0;
       while (n > 0) {
           int d = n % 10;
           n = n / 10;
           totalSum += d * d;
      }
       return totalSum;
  }

   public boolean isHappy(int n) {
       int slowRunner = n;
       int fastRunner = getNext(n);
       while (fastRunner != 1 && slowRunner != fastRunner) {
           slowRunner = getNext(slowRunner);
           fastRunner = getNext(getNext(fastRunner));
      }
       return fastRunner == 1;
  }
}

复杂度分析

方法三:数学

代码随想录

代码随想路题解

思路

这道题目看上去貌似一道数学问题,其实并不是! 题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要! 正如:关于哈希表,你该了解这些!中所说,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。 所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。 判断sum是否重复出现就可以使用unordered_set。 还有一个难点就是求和的过程,如果对取数值各个位上的单数操作不熟悉的话,做这道题也会比较艰难。 C++代码如下:

class Solution {
public:
   // 取数值各个位上的单数之和
   int getSum(int n) {
       int sum = 0;
       while (n) {
           sum += (n % 10) * (n % 10);
           n /= 10;
      }
       return sum;
  }
   bool isHappy(int n) {
       unordered_set<int> set;
       while(1) {
           int sum = getSum(n);
           if (sum == 1) {
               return true;
          }
           // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
           if (set.find(sum) != set.end()) {
               return false;
          } else {
               set.insert(sum);
          }
           n = sum;
      }
  }
};

 

标签:202,数字,int,sum,快乐,哈希,我们,循环
来源: https://www.cnblogs.com/wltree/p/15437772.html