202. 快乐数

题目

202. 快乐数

要求

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

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

思路

这道题目我没有思路,该怎么说呢,数据归纳法,看到下面这组数据:

Digits Largest Next
1 9 81
2 99 162
3 999 243
4 9999 324
13 9999999999999 1053

可以看到的是无论多大的数字,最后经过计算总会回归到 3 位数,例如 9999 的下一个是 324,而 999 最后是 243,也就是说最后只有两种情况,一种是得到快乐数,最后结果是 1,另外一种就是无限循环,但是是在 243 以下循环,基于此,可以考虑使用递归的方法,看看结果如果是 1 或者之前出现过,那说明出现了环,就退出:

public boolean isHappy(int n) {
    int[] arr = new int[244];
    return myIsHappy(n, arr);
}

public boolean myIsHappy(int n, int[] arr) {
    if (n == 1) {
        return true;
    }
    if (n < 244 && arr[n] == 2) {
        return false;
    }
    int sum = getNext(n);
    if (sum < 244) {
        arr[sum]++;
    }
    return myIsHappy(sum, arr);
}

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

看到环,能想到啥,链表呀,这个可以看做是一个链表,要么结果为 1,要么是链表成环,可以使用一个数组做一个缓存,因为快慢指针肯定有计算过的,防止重复计算,代码如下:

public boolean isHappy(int n) {
    // arr 加一层缓存,防止计算 next 的时候重复计算
    int[] arr = new int[244];
    int slow = n;
    int fast = getNext(n, arr);
    while (fast != 1 && fast != slow) {
        slow = getNext(slow, arr);
        fast = getNext(getNext(fast, arr), arr);
    }
    return fast == 1;
}

private int getNext(int n, int[] arr) {
    if (n < 244 && arr[n] != 0) {
        return arr[n];
    }
    int sum = 0;
    while (n > 0) {
        int d = n % 10;
        n /= 10;
        sum += d * d;
    }
    if (n < 244) {
        arr[n] = sum;
    }
    return sum;
}
posted @ 2023-12-18 18:12  庄子游世  阅读(7)  评论(0编辑  收藏  举报