【LeetCode-数学】快乐数

题目描述

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

输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

题目链接: https://leetcode-cn.com/problems/happy-number/

思路1

一个数不是快乐数的原因是这个数在变换的过程中又回到这个数本身,从而产生了循环,例如2->4->16->37->58->89->145->42->20->4,4已经在之前出现过,所以产生了循环,无法转换到1,故2不是快乐数。我们使用set来记录已经出现过的数,代码如下:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> lookup;
        int a = 0;
        int r = 0;
        while(true){
            r = n%10;
            a += r*r;
            n /= 10;
            if(n==0){
                if(a==1) return true;
                if(lookup.find(a)!=lookup.end()) return false;
                else{
                    lookup.insert(a);
                    n = a;
                    a = 0;
                }
            }
        }
        return false;
    }
};

代码结构优化
下边的代码思路功能和上面的代码是一样的,只对代码结构进行了优化:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> lookup;
        while(lookup.find(n)==lookup.end()){
            lookup.insert(n);
            n = getNext(n);
            if(n==1) return true;
        }
        return false;
    }

    int getNext(int n){
        int a = 0;
        int r = 0;
        while(n!=0){
            r = n%10;
            a += r*r;
            n /= 10;
        }
        return a;
    }
};

思路2

思路1使用了额外的存储空间来记录每个数字是否出现过。
这个问题可以看过查找链表中是否有环的问题,所以可以使用快慢指针来做。

慢指针每次走一步,快指针每次走两步:

  • 如果快慢指针最终相遇了且快指针不等于1,则说明出现了循环,返回false;
  • 如果快指针等于1,则说明数字是快乐数。

代码如下:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> lookup;
        int slow = n;
        int fast = getNext(n);    // 注意快指针的起点不是n
        while(fast!=1 && slow!=fast){
            slow = getNext(slow);
            fast = getNext(getNext(fast));
        }
        return fast==1;
    }

    int getNext(int n){
        int a = 0;
        int r = 0;
        while(n!=0){
            r = n%10;
            a += r*r;
            n /= 10;
        }
        return a;
    }
};

上面的代码快慢指针的起始位置不同,还可以让快慢指针都从第一个位置开始。代码如下:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> lookup;
        int slow = n;
        int fast = n;
        while(fast!=1 && getNext(fast)!=1){
            slow = getNext(slow);
            fast = getNext(getNext(fast));
            if(slow==fast) return false;
        }
        return true;
    }

    int getNext(int n){
        int a = 0;
        int r = 0;
        while(n!=0){
            r = n%10;
            a += r*r;
            n /= 10;
        }
        return a;
    }
};
posted @ 2020-04-30 11:09  Flix  阅读(223)  评论(0编辑  收藏  举报