题目
编写一个算法来判断一个数 n 是不是快乐数。
快乐数定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,
也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。如果 n 是快乐数就返回 True ;不是,则返回 False 。
分析
本题开始一头雾水,因为可能无限循环。这题关键就在此。思考怎样会出现出现无限循环?也就是什么情况下会判定为非快乐数?
如果当前计算得到的各位平方和之前出现过,意味着就出现了循环,以后还是循环。。。这就相当于找一个数之前是否出现过。
这很明显就是用哈希中的set集合,因为集合不同的元素具有唯一性,用find查找集合即可。
代码
1 class Solution { 2 public: 3 //取每位上的数的平方之和 4 int sum(int n){ 5 int s = 0; 6 //如何取每位上的数?对10取余再除以10 7 while(n){ 8 s += (n%10) * (n%10); 9 n /= 10; 10 } 11 return s; 12 } 13 bool isHappy(int n) { 14 unordered_set<int>st; 15 while(1){ 16 int res = sum(n); 17 if(res == 1) return true; 18 auto it = st.find(res); 19 if(it != st.end()) return false; 20 st.insert(res); 21 n = res; 22 } 23 } 24 };
法二、快慢指针判断循环,其实就是弗洛伊德判圈算法(龟兔赛跑)
想象一下,假设有两个小孩子在一个“可以无限向前跑”的跑道上赛跑,同时出发,但其中一个小孩的速度是另一个的两倍。如果跑道是直的,跑的快的永远在前面;但是如果跑道有环的话,则跑的快的小孩子将追上跑的慢的小孩。就是套圈了!
快指针每次比慢指针多走一步,所以快指针的路程的慢指针的2倍,当慢指针走完一圈,快指针正好走完两圈,两指针重合。
class Solution { public: //取每位上的数的平方之和 int sum(int n){ int s = 0; //如何取每位上的数?对10取余再除以10 while(n){ s += (n%10) * (n%10); n /= 10; } return s; } bool isHappy(int n) { int slow = sum(n); int fast = sum(sum(n)); while(fast != slow ){ slow = sum(slow); fast = sum(sum(fast)); } return slow == 1; } };
注意非快乐数出现的死循环就是有环,判断有环用快慢指针,相遇说i明有环,最后看下相遇点是否是1
本题和链表中的判断是否有环一样