计算机史上首篇教你从算法问题提炼算法思想的文章
路人丙:“小夕,你說學算法有什么用呢?”
小夕:“好玩呀。”
路人丙:“算法問題那么多,現查現用不就好了?”
小夕:“好咯,既然你誠心誠意的問了~小夕就大發慈悲的震驚你( ̄? ̄)”
為什喵要學算法
聽小夕慢慢講哦。好像現在在低端程序員的圈子里經常流傳著“算法無用論”和“臨時抱佛腳論”,好像在有的人眼里,編程就是一個經驗活兒,甚至說體力活。小夕只能說,這種想法讓人聽了會很尷尬的,別人都不知道該如何勸他們。
?
如果一個人是半道轉行計算機,有這種想法是無可厚非的。但是甚至一些名校出身的大學生都會這樣想,小夕就覺得非常尷尬啦。
?
算法是什么呢?
?
小夕說,算法就是計算方法(已逃
?
學習算法的意義有很多,比如很現實的用算法框架解決某個問題(比如文件排序),再比如用算法將一個時間上不可能完成的任務變得可能(比如用算法優化優美的斐波那契問題),小夕不一一列舉。其實整個人工智能領域,高性能計算領域,最終都能納回到精簡的算法大框架里去。一句話,算法是計算機的精華。
算法的究極打開方式
好像很多人學算法就是背過各種算法然后刷幾道題,應付一下考試就過去了。事后工作多年也翻不開算法書幾次。小夕只能說,╮(╯▽╰)╭哎。
?
小夕覺得,最重要的還是學習每個算法問題中的算法思想。要解決的算法問題是無窮無盡的,但是諸多問題背后的算法思想確是相同的。所以你生生的背過了“解決排序問題可以用選擇排序、插入排序、歸并排序、快速排序、堆排序巴拉巴拉”,那么你只是成功解決了一個算法問題。但是如果你在排序問題的歸并排序方法中提煉出了divide-and-conquer思想(中文叫“分治”),那么恭喜你成功解決了一大堆的算法問題。
?
下面小夕就以計算最長公共子序列(以下簡稱FCS)這個經典算法問題來給大家深刻感受一下從算法問題中提煉算法思想的過程。
FCS問題
首先,序列嘛,可以簡單理解成字符串。比如“tsinghua”就是一個8字符的序列。
?
子序列呢,就是由序列中若干字符,按原相對次序構成。
?
比如下圖就是原序列(上)與它的一個子序列(下)。
注意上下的連線一定不能交叉哦。
?
而最長公共子序列,就是兩個序列的所有相同子序列中最長的那個。
?
比如序列didactical和序列advantage的最長公共子序列為data,你絕對不可能找出4個以上字符的公共子序列的。
?
下面就以計算序列didactical和序列advantage的最長公共子序列為例,開始吧~
一個純粹的思路
觀察一下這個問題,如果從字符串中間去想的話會感覺一團糟,所以從兩頭想啊。
?
是不是一下子靈感來啦?對于didactical和advantage的開頭,即d和a,那么只有三種情況:
1、????要么a在FCS中,且是第一位,而d一定不在FCS中。
2、????要么d在FCS中,且是第一位,而a一定不在FCS中。
3、????要么d和a均不在FCS的第一位。
?
哈?你想說d和a可不可以都在FCS的第一位?小夕救不了你了。。。
?
走到這里是不是就好像走到了一個分叉路口呢?每一種情況就是一條路。
?
想一下,進入每一條路后,其實此時又是一個新問題。比如進入情況1之后,我們就可以把第二個序列的第一個字母d給剔除掉了,所以就成了計算idactical和advantage的FCS問題了。
?
而計算這個新的FCS問題,與剛才的思路完全一樣呀,依然從頭上開始,對i和a分三種情況討論,然后進入每一種情況后,又是一個新的FCS問題。
?
誒?這個套路是不是似曾相識?對!這特喵的不就是學編程語言時講的遞歸調用嘛!既然每一次的套路都一樣,那就說明完全可以用一個函數反復調用自身來解決問題!
?
是不是靈感爆發啦?只要兩個序列的開頭字母不同,那就不停的重復下去唄~那如果開頭字母相同怎么辦呢?這還用說呀!那開頭的這個字母肯定是FCS中的一部分啊!然后把這個字母保存下來后,都剔掉繼續遞歸調用呀~比如didactical和dvantage,你說開頭的這個d是不是FCS中的!敢說不是,小夕。。。哼哼哼,小夕兇死你~
?
既然開頭字母要么相同,要么不同,反正最終都會遞歸調用。這時再考慮什么呢?顯然,我們只需要考慮遇到“空字符串”時該怎么辦就好了。
?
顯然,只要遭遇了空字符串,那么肯定就代表著這一條尋找公共子序列的路線結束了,我們就可以數一數在這條路線上遇到了多少次“首字母相同”的情況,把這些情況首尾接起來,不就是這個公共子序列嘛~
?
最后,我們把這好多個公共子序列擺出來,比一比哪個最長(咦?怎么感覺怪怪的),最長的那個不就是我們要的FCS嘛~
小夕煉金秘法
?
好啦~任務完成。睜大眼睛看著吧!小夕只演示一遍哦~
首先,我們開始的時候很踏實,從問題的起點開始,也就是從字符串的首字母開始,然后很踏實的分析每一種可能的情況。對于每一種可能情況都考慮在內,最后再考慮一下每種情況結束時的情況和處理方法。誒?這種做法叫什么?大聲告訴小夕~~這不就是小學就學過的枚舉法嘛~一種情況一種情況的列舉,別說你小學的時候沒做過這種事。當然啦,枚舉法也叫蠻力法、暴力法,是一個東西。這就是本解法的最關鍵的算法思想啊~新算法思想,get!
?
誒?等等,再深入的挖掘一下,剛才我是不是說我們很踏實的分析每一種可能的情況呢?這里有沒有算法思想呢?這就是divide-and-conquer思想啊!就是分治呀~將一個大問題,一分為二,甚至一分為三,然后分別取解決每一個分好的子問題,這種思想就是分治思想!get!想一想拿著這個思想,去扔到排序問題上去,是不是立刻發現你們當年死記硬背的歸并排序一下子就出來啦??有木有很激動~
?
然后繼續分析,我們哪里來的自信,去相信不停的遞歸調用下去會結束呢?萬一死循環了呢?想一想哪來的自信呢~
?
有沒有發現,我們每到達一個岔路時,最少會讓一個子序列的字符數量減少1吶!專業的說法是“問題的規模一定會減小”!這樣不停的遞歸調用下去(專業說法叫迭代),問題的規模早晚減小為0!這種思想提煉出來了沒~起個名字,叫減而治之!再總結一下,如果你發現你的遞歸會讓問題的規模一點點的減小,那么就可以解決問題!有了減而治之的思想,以后不就會刻意的尋找讓問題規模減小的方法了嘛~而不是無頭蒼蠅瞎蒙啦。
?
還能不能挖出來其他算法思想呢?唔,小夕暫時沒有啦~但是你看,一個FCS問題的一種解法,就最少包含了3+1個算法思想!(解決問題的途中用到了遞歸,也算思想吧QAQ)如果你事先拿著枚舉法、分治法、減而治之、遞歸去扔到這個FCS問題上去,那這個問題秒解呀~當然啦,提煉出來思想后,要深刻消化哦!
?
但是聰明的喵喵也想到了,枚舉法看起來開銷好大呀,這得讓計算機考慮多少種情況呀,累壞計算機寶寶了~于是,有沒有辦法讓計算機大幅度減少考慮的情況呢?期待小夕的下一篇從思想講算法的大作吧!
?
但是小夕寫下去的動力就是你們的小紅包呀(?????????)
總結
以上是生活随笔為你收集整理的计算机史上首篇教你从算法问题提炼算法思想的文章的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 构建时预渲染:网页首帧优化实践
- 下一篇: 微服务系列:Dubbo与SpringCl