leetcode 202. 快乐数 思考分析(哈希集合与双指针解)

107 阅读2分钟

1、题目

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

2、思考分析

对一个数不断进行get_sum操作,那么最终可能的结果有两种可能:
1、得到1
2、计算的数陷入某种循环,然后会有重复的数出现
如果得到1,直接返回true;
如果检测到重复数出现就返回false;
否则记录出现的数,并在while循环中对n进行更新。

 int get_sum(int n)
{
      int sum=0;
      while(n!=0)
      {
          sum+=(n%10)*(n%10);
          n = n/10;
      }
      return sum;
  }

3、哈希法解

class Solution {
public:
    int get_sum(int n)
    {
        int sum=0;
        while(n!=0)
        {
            sum+=(n%10)*(n%10);
            n = n/10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int sum=0;
        //sum,sum出现的频次
        unordered_set<int> set;
        while(1)
        {
            sum=get_sum(n);
            if(sum ==1) return true;
            //如果某个数重复出现,那么我们认为此时陷入了循环,则这个数不是快乐数
            else if(set.find(sum)!=set.end())
            {
                return false;
            }
            set.insert(sum);
            n=sum;
        }
    }
};

4、双指针解

在这里插入图片描述
我们得到的结果序列是一个隐式的链表。
隐式意味着我们没有实际的链表节点和指针,但数据仍然形成链表结构。
于是这个问题可以转换为检测一个链表是否有环。
这个问题可以使用快慢指针法来解决。我们不是只跟踪链表中的一个值,而是跟踪两个值,称为快跑者和慢跑者。在算法的每一步中,慢速在链表中前进 1 个节点,快跑者前进 2 个节点。
前进一次调用一次计算函数,前进两次调用两次计算函数。

class Solution {
public:
    int get_next(int n)
    {
        int sum=0;
        while(n!=0)
        {
            sum+=(n%10)*(n%10);
            n = n/10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int sum=0;
        int slow_runner = n;
        int fast_runner = get_next(n);
        while( fast_runner != 1 && slow_runner != fast_runner)
        {
            //更新slow_runner,slow_runner每次前进一步
            slow_runner = get_next(slow_runner);
            //更新fast_runner,fast_runner每次前进二步,所以调用两次getnext函数
            fast_runner = get_next(get_next(fast_runner));
        }
        if(fast_runner == 1) return true;
        return false;
    }
};