Leetcode - Happy Number

最近已经开始紧张的期末复习了,但是看到大家都在进行编程训练,为今年九月找工作做准备,我的心不能定。因为我知道,英国的成绩对我无意义,但是编程能力是我以后吃饭的家伙,我绝对不能落下。
之前一直在上普林斯顿的算法课。最后三周的课,每次上耗时太长,实在抽不出时间,而且自己已经明显过了之前的那种良好状态,很难再静下心听几个小时的,算法,课了。而且这个课对自己帮助到底有多大。说不清楚。之前的所有作业都是自己写的,但是现在回想起来好像都忘得差不多了,很难过。一定会找个时间把之前学过的东西都复习一遍的!
于是乎,决定开始刷题 + CS61B. 他们相对来说更加轻松点,而且对于找工作的帮助,功利的来说,更大点。以后每天至少刷一道题目,这个要求并不高吧。开始吧。


Paste_Image.png

我的解决:

public class Solution {
    public boolean isHappy(int n) {
        int pHead = n;
        int pTail = n;
        int sum = 0;
        while (sum != 1) {
            pHead = getSum(pHead);
            if (pHead == 1)
                return true;
            pTail = getSum(getSum(pTail));
            if (pHead == pTail)
                return false;
            sum = pHead;
        }
        return true;
    }

    private int getSum(int n) {
        int sum = 0;
        int digit = n % 10;
        int residual = n / 10;
        while (residual != 0) {
            sum += digit * digit;
            digit = residual % 10;
            residual = residual / 10;
        }
        sum += digit * digit;
        return sum;     
    }
    
    public static void main(String args[]) {
        Solution test = new Solution();
        System.out.println(test.isHappy(12));
    }
}

这个题目并不难,或者说,唯一的难点在于。如何判断这个数不是happy。
如果这个数不happy,那么他就会一直在循环里跑,然后计算机就会崩溃掉。
所以必须有个方法来检测某个数不happy.
于是我找了一个数 12

12
5
25
29
85
89
145
42
20
4
16
37
58
89

我发现其实他们是严格遵守映射关系的。于是乎,如果一个数不happy,那么,他的映射关系链上一定存在循环,比如这里的 89.就出现了循环,然后他会在这个循环链里按照规定的关系一直循环下去。所以, 12 是 不happy的。

那么,现在问题就归结到,如果判断,这个映射链是否循环呢?如何判断现在出来的这个数,在之前是否出现过呢?
网上最多的做法是,设置一个hash table,然后把这些数都放在hash table 中。那么, 89 也会在这个哈希表里有自己的位置。当第二次89出现时,按照哈希映射,他也会找到哈希表中相应的位置,然后发现这个位置被人占了。就知道,发生循环了。
但是哈希表也有他的问题。首先是,他得额外占内存来存放哈希表。而且加入起始输入的数是 1000000000. 哈希表(数列)就会触发resize()功能,让哈希表扩展到这么大,但是之后就直接判断出,该数是happy的,那么这么大的数列就只存放了这么一个数字,太浪费空间了。

下面我给出我网上找的别人写的用哈希表实现的代码。没有多大难度,都是利用Java写好的类。

public class Solution {
    public boolean isHappy(int n) {
        int newN = 0;
        HashSet<Integer> set = new HashSet<Integer>();

        while(!set.contains(n)){
            set.add(n);
            newN = 0;
            while(n != 0){
                newN += (n % 10) * (n % 10);
                n /= 10;
            }
            n = newN;

            if(n == 1) return true;
        }

        return false;
    }
}

我后来看人的评论,发现了一个更好的方法。
他们使用了一个算法,叫做,Floyd's cycle-finding algorithm
这个算法的模型是:

def floyd(f, x0):
    # Main phase of algorithm: finding a repetition x_i = x_2i
    # The hare moves twice as quickly as the tortoise and
    # the distance between them increases by 1 at each step.
    # Eventually they will both be inside the cycle and then,
    # at some point, the distance between them will be
    # divisible by the period λ.
    tortoise = f(x0) # f(x0) is the element/node next to x0.
    hare = f(f(x0))
    while tortoise != hare:
        tortoise = f(tortoise)
        hare = f(f(hare))

也就是用两个指针指着这个逻辑链,一开始都只在头部,比如说12.
然后头指针会指向下一个结点,5.判断下。
尾指针会指向以此刻位置为基准的,之后的第二个结点,即25.判断下尾指针和头指针是否相等,若相等,则说明存在循环。return false.
然后头指针指向25,尾指针指向85.。。
以此循环。。。

Paste_Image.png

然后参考的网址是,
http://en.wikipedia.org/wiki/Cycle_detection

当然,这个算法的原理我是不懂得。但的确很好用哈。工程师吗,那理论家的理论当作工具用就行了,原理这些事,交给理论家吧。他们反正也是闲着没事干的。

**
最后做下总结,这次作业,收获在于学习了Floyd's cycle-finding algorithm算法,即如何判断一个映射链中是否存在循环,是采用两个指针实现的。
**

Leetcode的第一次就这么完成了。希望可以坚持下去。
写这篇文章正好学习了一些markdown语法,感觉很好用啊!掌握了这么一门语法,以后就不需要word了。。。加粗什么的直接代码实现,方便快捷高效!
学校的复习压力很重。但是自己现在为了考试学习电气的东西,很没有热情,而且觉得是浪费时间。但是叶也说得挺对的。当我没有选择,只能做一件事时,就把他当作提高自己学习能力的一件事来做吧。

Good luck, Richado!

My code:

public class Solution {
    public boolean isHappy(int n) {
        if (n <= 0) {
            return false;
        }
        HashSet<Integer> set = new HashSet<Integer>();
        set.add(n);
        while (n != 1) {
            n = helper(n);
            if (set.contains(n)) {
                return false;
            }
            set.add(n);
        }
        return true;
    }
    
    private int helper(int n) {
        int base = 10;
        int ret = 0;
        while (n > 0) {
            ret += (n % 10) * (n % 10);
            n = n / 10;
        }
        return ret;
    }
}

比较简单。
上面说的其实就是快慢指针。但是快慢指针存在的问题是,有一些重复操作啊。
这是我踏入 Leetcode 的第一题。想想都过了一年半了。自己的水平,也早就比那时候强了太多。但反而更加感觉到自己的渺小。
继续努力吧,希望自己能有个好运气。

Anyway, Good luck, Richardo! -- 09/21/2016

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容