毫无疑问,解决算法问题一定不止5种方法,但是下面的五种方法可能更加有用。但是还是要记住,算法靠的是不停的练习,练习越多,很多问题就迎刃而解! 同样也必须记住,这五种方法不是单独的组成,它们可以混合在一起使用。也就是说,可能某一个算法的解决方法同时使用了下面两种方法。

          方法一:举例法

          描述:列举问题的例子,然后看看自己能不能计算出一个通用的答案

          例子:给定时钟上的某个时间,计算出时针和分针之间的形成的角度

          解决方法:首先举个例子,比如3:27,我们可以画一个简单的3时27分,两个针所形成的角度。通过多画出这个这样简单的例子,我们可以看到如下的规律:

                           (1)分针和12点方向之间形成的角度:360*minutes/60

                           (2)时针和12点方向之间形成的角度:360*(hours%12)/12+360*(minutes/60)*(1/12)

                           (3)时针和分针之间的角度:(hour angle - minute angle)  %360

        通过简单的算术运算,可以化简为 30*hours - 5.5*minutes


        方法二:相似问题联想

        描述:考虑遇到的这个问题和哪个问题比较相似,进而修改其解决方案来求解遇到的新的问题

        例子:将一个排序的数组进行旋转,比如说3、4、5、6、7、1、2,求解出这个数组中最小的元素

        相似的问题:(1)寻找一个数组中的最小的元素

                                (2)寻找一个数组中的特定的元素(比如二分法)

        算法:在一个数组中寻找最小的元素并不是一个很难的问题,只需要遍历数组中所有的元素。但是如果用这个方法来解决上述问题时,题目中的排序我们就没有使用到。然而,二分法是应用很广泛的。但是二分法的条件是递增的,而本题中的数组则是旋转递增的,也就是先是递增,然后从最小的元素再开始递增,最小的元素就是那个转折点。就本题中的数字而言,当比较第一个元素和中间元素(3和6)的时候,可以看到这个范围中的元素还是递增的。这就意味着转折点一定在6的后面(或者3就是最小的元素,这个数组根本没有旋转)。我们可以继续利用二分法寻找,对于任何一个区间,如果左边的元素小于右边,则转折点不在其中,如果大于则在其中。


        方法三:简化

        描述:改变一个题目中的一个限制条件(数据类型,大小等)来简化问题,然后再来解决原来的问题。一旦找到了简化问题的解决方法,再来归纳原问题的解决方案。

        例子:统计一篇文章中单词出现的次数。

        简化:首先我们不先解决有单词组成的问题,而是由字母组成的情况。也就是想象一下我们将一个杂志按照一个个的字母来归类。

        算法:我们可以通过构造一个简单的数组,然后统计字母的个数的方式来解决这个简化的问题。数组中的每一个点对应一个字母。首先我们计算每一个字母在清单中出现的次数,然后通过浏览整个文章来查看是不是我们统计了整个文章的全部字母。

        当我们泛化这个算法得到一般问题的解决方案时,可以很容易的得到,我们可以像构造数组一样构造一个哈希表,每一个单词为一个元素并且统计出现的次数。


       方法四:

       描述:面对一个问题,首先解决一个最简单最基本的情况(比如只有一个元素的时候),然后试图两个,并且假设你已经得到了一个元素的解。然后试图三个,不要忘记你已经知道一个和两个时候的解。

       例子:设计一个算法打印一个字符串所有的排列情况。为了简化,假设所有的字符没有重复。

       测试字符串:abcdefg

       Case "a"  -->  {a}

       Case "ab"   -->  {ab,ba}

       Case   "abc"   -->{?}

        这是一个有趣的例子,如果我们已经有了P(“ab”)的答案,我们怎么产生P(“abc”)的答案呢?我们可以看到,增加的字母是“c”,所以我们只需要看c可能的位置。归纳如下:

        merge(c,ab)  --> {cab,acb,abc}

        merge(c,ba)   -->{aba,bca,bac}

        算法:使用一个递归算法,通过将字符串的最后一个字符和前面n-1个字符的答案进行求解,将最后一个元素放到可以放置的任何一个可能的位置产生答案。


        方法五:“数据结构风暴”

        描述:这种方法是简单的,但是也是很有效的,容易掌握的。就是在做题时将自己学到的每一个数据结构进行选择,然后找出能够使用本题答案的数据结构。

        例子:随机产生一组数并且存在可以可扩充的数组中,如何标记数组的中位数?

        数据结构头脑风暴: 

        >> 链表?--可能不是,因为链表在直接访问和排序方面的没有优势。

        >>数组?--但是我们已经有了一个数组,如果再将元素排序放到一个数组中,也许时间和空间复杂度不是很好。先放在这儿,如果没有更好的,我们再返回到这儿。

        >>二叉树? --这个是有可能的,因为二叉树在排序方面的性能很好。事实上,如果二叉树是完美平衡的,那么最顶上的元素就是最大的元素。但是,这里有个小问题,如果元素的个数是偶数个,中位数是最顶端两个元素的平均,而中间两个元素不可能同时位于最顶端,这是可能要考虑的情况,我们一会儿再来想这些细节。

        >>堆? --在基本的排序和查找最大最小元素的算法中,堆的性能非常的好。如果有两个堆,你就可以将一堆元素分成打一半的元素和小一半的元素。大一半的元素使用小根堆,这样大一半元素中的最小元素就在堆的最顶端。同样,小一半的元素使用大根堆,小一半的元素中最大的元素就在最顶端。使用这样的数据源结构,就将可能的中位数放在了两个堆的顶端。如果两个堆的元素不相同,你就可以迅速的将元素多的堆中将元素移到元素比较少的堆中。

         最后强调算法还是要多做题目,你所遇到的和处理的问题越多,在选择数据结构和算法的过程中就越灵活。