① 程序員是怎樣解決問題的
程序員的五部曲:
第一、理解問題
解決問題的首要前提是客觀准確地理解問題,這樣我們才能抓住問題的本質,對症下葯。
客觀
為什麼強調客觀呢?在生活中,這樣的情境很常見。
我們可以很客觀地去評價他人,甚至是給他人給出合理的意見,但是同樣的一件事情,放到我們自己身上,我們可能就會覺得束手無策。
通常情況下,我們對於自己的評價是帶走自我保護心理的。
自己遇到問題,我們會下意識地弱化問題,或者情緒化地來理解問題,造成問題的失真。
魔鏡的故事就是一個最典型的例子。
准確
當我們對自身的問題評價做不到客觀的時候,我們往往也不會准確理解問題。
還有,准確的定義是找到問題的關鍵所在。這個怎麼做呢?
我們仿照時間管理的方式。
首先對自己所要解決問題的過程做一個較為詳細的記錄。
堅持記錄幾天之後,我們需要將所有的記錄結果進行匯總,分析,找出漏洞最大的地方。
那麼這個洞也就是所謂的關鍵,我們也就可以找到解決問題的突破口。
舉個例子,筆者前段時間開始用手機軟體記錄自己的時間花銷,記錄幾天之後,就會發現,自己時間浪費最為嚴重的是娛樂。
知道了時間浪費的黑洞,那麼接下來就該思考時間黑洞產生的原因了。
時間浪費的主要原因是兩個
第一,目標流失
當我在網上查資料,或者用手機寫作的時候,總會進入其他的瀏覽頁面,等到自己發覺的時候,時間已經過去大半。
這個我稱之為目標流失。也就是我們在網頁瀏覽的時候已經忘記了自己最初的目的,比如說你本來想找一本書籍的txt版本,但是後來你發現自己瀏覽了一下午的娛樂新聞。
第二,多任務處理
這個問題我是經常遇到。比如說,我在進行日更的時候,有新同學發微信,說查一下宿舍的分配情況。
我當時的反應是火急火燎地去其刷微信,信息查詢完畢之後,和分配在同一宿舍的同學聊了一下午。
最要命的是,等到你刷完屏的時候,你有很大可能會忘掉你在更這件事。
或者說你還記得,但你的精力已經消耗的差不多了,你會告訴自己,等會再更,然後你有很大的概率會斷更。
找到時間黑洞形成的原因,那麼就可以尋求解決措施了。
第二、計劃
為自己的病症設置一個完整的療程,根據問題出現的原因,制定每一步要採取的手段。
第三、拆解
這一步是和計劃聯系在一起的,只不過它的要求更加細化。
它需要我們將計劃的每一步都拆解成可以執行的步驟,感興趣的讀者可以參考筆者的另外一篇文章《如何讓遙不可及的夢想變得觸手可及?》
第四、卡殼
可以說,我們每個人都有改變的想法,也確實有很多人嘗試去做了,為什麼還有那麼多的放棄者。
因為在執行計劃的時候,出現的變數讓我們卡殼了。卡殼再正常不活了,那為什麼會放棄?
答案是自我負罪感。
當我們卡殼的時候,我們大多數人會產生一種負罪感,就是覺得自己定計劃的時候,詳盡完備,而且自己已經堅持了這么長時間,會陷入一種自我懷疑,也就是負罪感。
解決的辦法是立即採取行動,而不是描述問題本身,這也是我們解決所有問題的一個心態。
我們不要緊盯著問題本身,你理解問題的過程就是在採取行動,相反,你逢人就說,我遇到什麼問題,我有多痛苦,沒有任何意義。
第五、練習
其實這個步驟是對前面幾步的一個綜合。
這五部曲是一個閉環,是需要反復進行的,因為問題會不斷出現。
回頭看過去的生活,我們的歷程何嘗不是這樣?不斷遇到新問題,不斷解決問題,然後獲得新的體驗。
想看更多文章
歡迎關注大魚號【小妖影視】
② 75道程序員面試邏輯測試題(附答案)(1)
【1】 假設有一個池塘,裡面有無窮多的水。現有2個空水壺,容積分別為5升和6升。問題是如何只用這2個水壺從池塘里取得3升的水。
由滿6向空5倒,剩1升,把這1升倒5里,然後6剩滿,倒5裡面,由於5裡面有1升水,因此6隻能向5倒4升水,然後將6剩餘的2升,倒入空的5裡面,再灌滿6向5里倒3升,剩餘3升。
【2】 周雯的媽媽是豫林水泥廠的化驗員。一天,周雯來到化驗室做作業。做完後想出去玩。"等等,媽媽還要考你一個題目,"她接著說,"你看這6隻做化驗用的玻璃杯,前面3隻盛滿了水,後面3隻是空的。你能只移動1隻玻璃杯,就便盛滿水的杯子和空杯子間隔起來嗎?"愛動腦筋的周雯,是學校里有名的"小機靈",她只想了一會兒就做到了。請你想想看,"小機靈"是怎樣做的?
設杯子編號為ABCDEF,ABC為滿,DEF為空,把B中的水倒進E中即可。
【3】 三個小夥子同時愛上了一個姑娘,為了決定他們誰能娶這個姑娘,他們決定用手槍進行一次決斗。小李的命中率是30%,小黃比他好些,命中率是50%,最出色的槍手是小林,他從不失誤,命中率是100%。由於這個顯而易見的事實,為公平起見,他們決定按這樣的順序:小李先開槍,小黃第二,小林最後。然後這樣循環,直到他們只剩下一個人。
那麼這三個人中誰活下來的機會最大呢?他們都應該採取什麼樣的策略?
小林在輪到自己且小黃沒死的條件下必殺黃,再跟菜鳥李單挑。
所以黃在林沒死的情況下必打林,否則自己必死。
小李經過計算比較(過程略),會決定自己先打小林。
於是經計算,小李有873/2600≈33.6%的生機;
小黃有109/260≈41.9%的生機;
小林有24.5%的生機。
哦,這樣,那小李的第一槍會朝天開,以後當然是打敵人,誰活著打誰;
小黃一如既往先打林,小林還是先幹掉黃,冤家路窄啊!
最後李,黃,林存活率約38:27:35;
菜鳥活下來抱得美人歸的幾率大。
李先放一空槍(如果合夥干中林,自己最吃虧)黃會選林打一槍(如不打林,自己肯定先玩完了)林會選黃打一槍(畢竟它命中率高)李黃對決0.3:0.280.4可能性李林對決0.3:0.60.6可能性成功率0.73
李和黃打林李黃對決0.3:0.40.7 0.4可能性李林對決0.3:0.7 0.6 0.70.7 0.6可能性成功率0.64
【4】 一間囚房裡關押著兩個犯人。每天監獄都會為這間囚房提供一罐湯,讓這兩個犯人自己來分。起初,這兩個人經常會發生爭執,因為他們總是有人認為對方的湯比自己的多。後來他們找到了一個兩全其美的辦法:一個人分湯,讓另一個人先選。於是爭端就這么解決了。可是,現在這間囚房裡又加進來一個新犯人,現在是三個人來分湯。必須尋找一個新的方法來維持他們之間的和平。該怎麼辦呢?按:心理問題,不是邏輯問題
是讓甲分湯,分好後由乙和丙按任意順序給自己挑湯,剩餘一碗留給甲。這樣乙和丙兩人的總和肯定是他們兩人可拿到的最大。然後將他們兩人的湯混合之後再按兩人的方法再次分湯。
【5】 在一張長方形的桌面上放了n個一樣大小的圓形硬幣。這些硬幣中可能有一些不完全在桌面內,也可能有一些彼此重疊;當再多放一個硬幣而它的圓心在桌面內時,新放的硬幣便必定與原先某些硬幣重疊。請證明整個桌面可以用4n個硬幣完全覆蓋。
要想讓新放的硬幣不與原先的硬幣重疊,兩個硬幣的圓心距必須大於直徑。也就是說,對於桌面上任意一點,到最近的圓心的距離都小於2,所以,整個桌面可以用n個半徑為2的硬幣覆蓋。
把桌面和硬幣的尺度都縮小一倍,那麼,長、寬各是原桌面一半的小桌面,就可以用n個半徑為1的硬幣覆蓋。那麼,把原來的桌子分割成相等的4塊小桌子,那麼每塊小桌子都可以用n個半徑為1的硬幣覆蓋,因此,整個桌面就可以用4n個半徑為1的硬幣覆蓋。
【6】 一個球、一把長度大約是球的直徑2/3長度的直尺.你怎樣測出球的半徑?方法很多,看看誰的比較巧妙
把球放在平面上,把直尺的一邊卡在平面上,一邊卡在球上,球與尺子的接觸點到平面的距離就是球的半徑.因為直尺長度約為直徑的2/3>半徑,所以能測量.
【7】 五個大小相同的一元人民幣硬幣。要求兩兩相接觸,應該怎麼擺?
底下放一個1,然後2 3放在1上面,另外的4 5豎起來放在1的上面。
【8】 猜牌問題S先生、P先生、Q先生他們知道桌子的抽屜里有16張撲克牌:紅桃A、Q、4黑桃J、8、4、2、7、3草花K、Q、5、4、6方塊A、5。約翰教授從這16張牌中挑出一張牌來,並把這張牌的點數告訴P先生,把這張牌的花色告訴Q先生。這時,約翰教授問P先生和Q先生:你們能從已知的點數或花色中推知這張牌是什麼牌嗎?於是,S先生聽到如下的對話:P先生:我不知道這張牌。Q先生:我知道你不知道這張牌。P先生:現在我知道這張牌了。Q先生:我也知道了。聽罷以上的對話,S先生想了一想之後,就正確地推出這張牌是什麼牌。請問:這張牌是什麼牌? 方塊5
【9】 一個教授邏輯學的教授,有三個學生,而且三個學生均非常聰明!一天教授給他們出了一個題,教授在每個人腦門上貼了一張紙條並告訴他們,每個人的紙條上都寫了一個正整數,且某兩個數的和等於第三個!(每個人可以看見另兩個數,但看不見自己的)教授問第一個學生:你能猜出自己的數嗎?回答:不能,問第二個,不能,第三個,不能,再問第一個,不能,第二個,不能,第三個:我猜出來了,是144!教授很滿意的笑了。請問您能猜出另外兩個人的數嗎?
經過第一輪,說明任何兩個數都是不同的。第二輪,前兩個人沒有猜出,說明任何一個數都不是其它數的兩倍。現在有了以下幾個條件:1.每個數大於02.兩兩不等3.任意一個數不是其他數的兩倍。每個數字可能是另兩個之和或之差,第三個人能猜出144,必然根據前面三個條件排除了其中的一種可能。假設:是兩個數之差,即x-y=144。這時1(x,y>0)和2(x!=y)都滿足,所以要否定x+y必然要使3不滿足,即x+y=2y,解得x=y,不成立(不然第一輪就可猜出),所以不是兩數之差。因此是兩數之和,即x+y=144。同理,這時1,2都滿足,必然要使3不滿足,即x-y=2y,兩方程聯立,可得x=108,y=36。
這兩輪猜的順序其實分別為這樣:第一輪(一號,二號),第二輪(三號,一號,二號)。這樣分大家在每輪結束時獲得的信息是相同的(即前面的三個條件)。
那麼就假設我們是C,來看看C是怎麼做出來的:C看到的是A的36和B的108,因為條件,兩個數的和是第三個,那麼自己要麼是72要麼是144(猜到這個是因為72的話,108就是36和72的和,144的話就是108和36的和。這樣子這句話看不懂的舉手):
假設自己(C)是72的話,那麼B在第二回合的時候就可以看出來,下面是如果C是72,B的思路:這種情況下,B看到的就是A的36和C的72,那麼他就可以猜自己,是36或者是108(猜到這個是因為36的話,36加36等於72,108的話就是36和108的和):
如果假設自己(B)頭上是36,那麼,C在第一回合的時候就可以看出來,下面是如果B是36,C的思路:這種情況下,C看到的就是A的36和B的36,那麼他就可以猜自己,是72或者是0(這個不再解釋了):
如果假設自己(C)頭上是0,那麼,A在第一回合的時候就可以看出來,下面是如果C是0,A的思路:這種情況下,A看到的就是B的36和C的0,那麼他就可以猜自己,是36或者是36(這個不再解釋了),那他可以一口報出自己頭上的36。(然後是逆推逆推逆推),現在A在第一回合沒報出自己的36,C(在B的想像中)就可以知道自己頭上不是0,如果其他和B的想法一樣(指B頭上是36),那麼C在第一回合就可以報出自己的72。現在C在第一回合沒報出自己的36,B(在C的想像中)就可以知道自己頭上不是36,如果其他和C的想法一樣(指C頭上是72),那麼B在第二回合就可以報出自己的108。現在B在第二回合沒報出自己的108,C就可以知道自己頭上不是72,那麼C頭上的唯一可能就是144了。
史上最雷人的應聘者
【10】 某城市發生了一起汽車撞人逃跑事件,該城市只有兩種顏色的車,藍15%綠85%,事發時有一個人在現場看見了,他指證是藍車,但是根據專家在現場分析,當時那種條件能看正確的可能性是80%那麼,肇事的車是藍車的概率到底是多少?
15% 80%/(85%×20%+15% 80%)
【11】 有一人有240公斤水,他想運往乾旱地區賺錢。他每次最多攜帶60公斤,並且每前進一公里須耗水1公斤(均勻耗水)。假設水的價格在出發地為0,以後,與運輸路程成正比,(即在10公里處為10元/公斤,在20公里處為20元/公斤......),又假設他必須安全返回,請問,他最多可賺多少錢?
f(x)=(60-2x)*x,當x=15時,有最大值450。
450×4
【12】 現在共有100匹馬跟100塊石頭,馬分3種,大型馬;中型馬跟小型馬。其中一匹大馬一次可以馱3塊石頭,中型馬可以馱2塊,而小型馬2頭可以馱一塊石頭。問需要多少匹大馬,中型馬跟小型馬?(問題的關鍵是剛好必須是用完100匹馬) 6種結果
【13】 1=5,2=15,3=215,4=2145那麼5=?
因為1=5,所以5=1.
【14】 有2n個人排隊進電影院,票價是50美分。在這2n個人當中,其中n個人只有50美分,另外n個人有1美元(紙票子)。愚蠢的電影院開始賣票時1分錢也沒有。問:有多少種排隊方法使得每當一個擁有1美元買票時,電影院都有50美分找錢
註:1美元=100美分擁有1美元的人,擁有的是紙幣,沒法破成2個50美分
本題可用遞歸演算法,但時間復雜度為2的n次方,也可以用動態規劃法,時間復雜度為n的平方,實現起來相對要簡單得多,但最方便的就是直接運用公式:排隊的種數=(2n)!/[n!(n+1)!]。
如果不考慮電影院能否找錢,那麼一共有(2n)!/[n!n!]種排隊方法(即從2n個人中取出n個人的組合數),對於每一種排隊方法,如果他會導致電影院無法找錢,則稱為不合格的,這種的排隊方法有(2n)!/ (n-1)!(n+1)! 種,所以合格的排隊種數就是(2n)!/[n!n!]- (2n)!/[(n-1)!(n+1)!] =(2n)!/[n!(n+1)!]。至於為什麼不合格數是(2n)!/[(n-1)!(n+1)!],說起來太復雜,這里就不講了。
【15】 一個人花8塊錢買了一隻雞,9塊錢賣掉了,然後他覺得不劃算,花10塊錢又買回來了,11塊賣給另外一個人。問他賺了多少?
2元
【16】 有一種體育競賽共含M個項目,有運動員A,B,C參加,在每一項目中,第一,第二,第三名分別的X,Y,Z分,其中X,Y,Z為正整數且X>Y>Z。最後A得22分,B與C均得9分,B在百米賽中取得第一。求M的值,並問在跳高中誰得第二名。
因為ABC三人得分共40分,三名得分都為正整數且不等,所以前三名得分最少為6分,40=5 8=4 10=2 20=1 20,不難得出項目數只能是5.即M=5.
A得分為22分,共5項,所以每項第一名得分只能是5,故A應得4個一名一個二名.22=5*4+2,第二名得1分,又B百米得第一,所以A只能得這個第二.
B的5項共9分,其中百米第一5分,其它4項全是1分,9=5+1=1+1+1.即B除百米第一外全是第三,跳高第二必定是C所得.
【17】 前提:
1 有五棟五種顏色的房子
2 每一位房子的主人國籍都不同
3 這五個人每人只喝一種飲料,只抽一種牌子的香煙,只養一種寵物
4 沒有人有相同的寵物,抽相同牌子的香煙,喝相同的飲料
提示:1 英國人住在紅房子里
2 瑞典人養了一條狗
3 丹麥人喝茶
4 綠房子在白房子左邊
5 綠房子主人喝咖啡
6 抽PALLMALL煙的人養了一隻鳥
7 黃房子主人抽DUNHILL煙
8 住在中間那間房子的人喝牛奶
9 挪威人住第一間房子
10抽混合煙的人住在養貓人的旁邊
11養馬人住在抽DUNHILL煙的人旁邊
12抽BLUEMASTER煙的人喝啤酒
13德國人抽PRINCE煙
14挪威人住在藍房子旁邊
15抽混合煙的人的鄰居喝礦泉水
問題是:誰養魚???
第一間是黃房子,挪威人住,喝礦泉水,抽DUNHILL香煙,養貓;! f/ [% a: 6 L! J. Q9 x第二間是藍房子,丹麥人住,喝茶,抽混合煙,養馬;+ o8 _0 S) L8 i' E' u第三間是紅房子,英國人住,喝牛奶,抽PALL MALL煙,養鳥;/ N9 o/ n2 M# U" c第四間是綠房子,德國人住,喝咖啡,抽PRINCE煙,養貓、馬、鳥、狗以外的寵物;7 P5 l) G, G, |; C, {7 V第五間是白房子,瑞典人住,喝啤酒,抽BLUE MASTER煙,養狗。
【18】 5個人來自不同地方,住不同房子,養不同動物,吸不同牌子香煙,喝不同飲料,喜歡不同食物。根據以下線索確定誰是養貓的人。
10.養魚的人住在最右邊的房子里。
11.吸萬寶路香煙的人住在吸希爾頓香煙的人和吸「555」香煙的人的中間(緊鄰)
12.紅房子的人愛喝茶。
13.愛喝葡萄酒的人住在愛吃豆腐的人的右邊隔壁。
14.吸紅塔山香煙的人既不住在吸健牌香煙的人的隔壁,也不與來自上海的人相鄰。
15.來自上海的人住在左數第二間房子里。
16.愛喝礦泉水的人住在最中間的房子里。
17.愛吃面條的人也愛喝葡萄酒。
18.吸「555」香煙的人比吸希爾頓香煙的人住的靠右
第一間是蘭房子,住北京人,養馬,抽健牌香煙,喝茅台,吃豆腐;2 G7 x% z0 v; C第二間是綠房子,住上海人,養狗,抽希爾頓,喝葡萄酒,吃面條;% C2 k4 o8 t" p6 L* x第三間是黃房子,住香港人,養蛇,抽萬寶路,喝礦泉水,吃牛肉;& N" S% x# o3 a; g第四間是紅房子,住天津人,抽555,喝茶,吃比薩;7 5 s. J# d, Q/ N% N' O# ]第五間是白房子,住成都人,養魚,抽紅塔山,喝啤酒,吃雞。
【19】 鬥地主附殘局
地主手中牌2、K、Q、J、10、9、8、8、6、6、5、5、3、3、3、3、7、7、7、7
長工甲手中牌大王、小王、2、A、K、Q、J、10、Q、J、10、9、8、5、5、4、4
長工乙手中牌2、2、A、A、A、K、K、Q、J、10、9、9、8、6、6、4、4
三家都是明手,互知底牌。要求是:在三家都不打錯牌的情況下,地主必須要麼輸要麼贏。問:哪方會贏?
無解地主怎麼出都會輸
【20】 一樓到十樓的每層電梯門口都放著一顆鑽石,鑽石大小不一。你乘坐電梯從一樓到十樓,每層樓電梯門都會打開一次,只能拿一次鑽石,問怎樣才能拿到最大的一顆?
先拿下第一樓的鑽石,然後在每一樓把手中的鑽石與那一樓的鑽石相比較,如果那一樓的鑽石比手中的鑽石大的話那就把手中的鑽石換成那一層的鑽石。
③ 程序員邏輯推理 圖形題 怎麼做
一般是兩個圖形疊加成為另一個,在一定順序上旋轉,每個特定元素出現特定次數。反正智商圖形題部分可以這么解。
④ 程序員演算法解題方法與思路
此方法通過寫出問題的一些特定的例子,分析總結其中的規律。具體而言,就是通過列舉少量的特殊情況,經過分析,最後找出一般的關系。
問題與以前莫個演算法解決過的問題相似,此時就可以觸類旁通,嘗試改進原有演算法來解決
此方法首先將問題簡單化,如改變數據類型、空間大小等,然後嘗試著將簡化後的問題解決。
為了降低問題的復雜度,很多時候都會將問題逐層分解,最後歸結為一些簡單的問題,這就是遞歸法
將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。分治法一般包括以下三個步驟:
1)將問題的實例劃分為幾個較小的實例,最好最有相等的規模。
2)對這些較小的實例求解,而最常見的方法一般是遞歸。
3)如歌有必要,合並這些較小問題的解,以得到原始問題的解。
一般而言,時間復雜度越低的演算法越高效。而更想達到時間復雜度的高效,很多時候就必須在空間上有所犧牲,用空間來換時間。而用空間換時間最有效的方法就是Hash法、大數組和點陣圖法。
在設計題目時,往往會有一個載體,這個載體便是數據結構。如數組、鏈表、二叉樹和圖等,當窄體確定後,可用的演算法自然而然就會顯現出來。可問題是很多時候並不確定這個載體是什麼,當無法確定這個載體時,一般也就很難想到合適的方法了。
當遇到上面的問題時,可以採用最原始的思考問題的方式——輪詢法。常考的數據結構與演算法一共就幾種,如下圖
此種方法看似笨拙,卻很實用,只要對常見的數據結構與演算法爛熟於心,一點都沒有問題。
⑤ 程序員演算法實現-買賣股票的最佳時機系列問題
主要思路:因為只有一股可以交易,所以我們可以枚舉 必須以i位置作為賣出時機的情況下,得到的最大收益是多少。如果我們得到每個i位置的最大收益,那麼最大收益必是所有位置的最大收益的最大值 。
使用兩個變數:
min變數:表示遍歷到的位置之前的最小值是什麼。
max變數:表示當前收集到必須以i位置賣出的最大收益是多少。
遍歷數組一遍,在遍歷到i位置的時候,min和max的更新邏輯如下:
遍歷完數組,返回max的值就是最終答案。完整代碼見:
主要思路:由於可以進行任意次的交易,但是任何時候最多隻能持有一股股票,所以我們可以把股票曲線的所有 上升段 都抓取到,累加收益就是最大收益。遍歷數組,遍歷到的位置減去前一個位置的值,如果是正數,就收集,如果是負數,就把本次收益置為0(就等於沒有做這次交易),這樣遍歷一遍數組,就不會錯過所有的收益。
設置一個變數max,初始為0,用於收集最大收益值,來到i位置,max更新邏輯如下:
完整代碼如下:
由本題可以簡單得出一個結論: 如果數組元素個數為N,則最多執行N/2次交易就可以抓取所有的上升段的值(極端情況下,當前時刻買,下一個時刻賣,保持這樣的交易一直到最後,執行的交易次數就是N/2) 。
主要思路:
在第2種情況下,我們定義
其中dp[i][j]表示[0...i]范圍內交易j次獲得的最大收益是多少。如果可以把dp這個二維表填好,那麼返回dp[N-1][k]的值就是題目要的答案。
dp這個二維矩陣中,
第一行的值表示數組[0..0]范圍內,交易若干次的最大收益,顯然,都是0。
第一列的值表示數組[0...i]范圍內,交易0次獲得的最大收益,顯然,也都是0。
針對任何一個普遍位置dp[i][j]的值,
我們可以枚舉i位置是否參與交易,如果i位置不參與交易,那麼dp[i][j] = dp[i-1][j],如果i位置參與交易,那麼i位置一定是最後一次的賣出時機。
那最後一次買入的時機,可以是如下情況:
最後一次買入的時機在i位置,那麼dp[i][j] = dp[i][j-1] - arr[i] + arr[i]
最後一次買入的時機在i-1位置,那麼dp[i][j] = dp[i-1][j-1] - arr[i-1] + arr[i]
最後一次買入的時機在i-2位置,那麼dp[i][j] = dp[i-2][j-1] - arr[i-2] + arr[i]
...
最後一次買入的時機在0位置,那麼dp[i][j] = dp[0][j-1] - arr[0] + arr[i]
完整代碼如下:
上述代碼中包含一個枚舉行為
增加了時間復雜度,我們可以優化這個枚舉。
我們可以舉一個具體的例子來說明如何優化,
比如,
當我們求dp[5][3]這個值,我們可以枚舉5位置是否參與交易,假設5位置不參與交易,那麼dp[5][3] = dp[4][3],假設5位置參與交易,那麼5位置一定是最後一次的賣出時機。那最後一次買入的時機,可以是如下情況:
最後一次買入的時機在5位置,那麼dp[5][3] = dp[5][2] - arr[5] + arr[5]
最後一次買入的時機在4位置,那麼dp[5][3] = dp[4][2] - arr[4] + arr[5]
最後一次買入的時機在3位置,那麼dp[5][3] = dp[3][2] - arr[3] + arr[5]
最後一次買入的時機在2位置,那麼dp[5][3] = dp[2][2] - arr[2] + arr[5]
最後一次買入的時機在1位置,那麼dp[5][3] = dp[1][2] - arr[1] + arr[5]
最後一次買入的時機在0位置,那麼dp[5][3] = dp[0][2] - arr[0] + arr[5]
我們求dp[4][3]這個值,我們可以枚舉4位置是否參與交易,假設4位置不參與交易,那麼dp[4][3] = dp[3][3],假設4位置參與交易,那麼4位置一定是最後一次的賣出時機。那最後一次買入的時機,可以是如下情況:
最後一次買入的時機在4位置,那麼dp[4][3] = dp[4][2] - arr[4] + arr[4]
最後一次買入的時機在3位置,那麼dp[4][3] = dp[3][2] - arr[3] + arr[4]
最後一次買入的時機在2位置,那麼dp[4][3] = dp[2][2] - arr[2] + arr[4]
最後一次買入的時機在1位置,那麼dp[4][3] = dp[1][2] - arr[1] + arr[4]
最後一次買入的時機在0位置,那麼dp[4][3] = dp[0][2] - arr[0] + arr[4]
比較dp[5][3]和dp[4][3]的依賴關系,可以得到如下結論:
假設在求dp[4][3]的過程中,以下遞推式的最大值我們可以得到
dp[4][2] - arr[4]
dp[3][2] - arr[3]
dp[2][2] - arr[2]
dp[1][2] - arr[1]
dp[0][2] - arr[0]
我們把以上式子的最大值定義為best,那麼
dp[5][3] = Math.max(dp[4][3],Math.max(dp[5][2] - arr[5] + arr[5], best + arr[5]))
所以dp[5][3]可以由dp[4][3]加速得到,
同理,
dp[4][3]可以通過dp[3][3]加速得到,
dp[3][3]可以通過dp[2][3]加速得到,
dp[2][3]可以通過dp[1][3]加速得到,
dp[1][3]可以很簡單得出,dp[1][3]有如下幾種可能性:
可能性1,1位置完全不參與,則
可能性2,1位置作為最後一次的賣出時機,買入時機是1位置
可能性3,1位置作為最後一次的賣出時機,買入時機是0位置
此時,best的值為
然後通過dp[1][3]加速dp[2][3],通過dp[2][3]加速dp[3][3]......,所以二維dp的填寫方式是按列填,
先填dp[1][0],dp[1][2]一直到dp[1][k],填好第一列;
然後填dp[2][0],dp[2][1]一直到dp[2][k],填好第二列;
...
依次填好每一列,直到填完第N-1列。
枚舉行為被優化,優化枚舉後的完整代碼如下:
主要思路:上一個問題中,令k=2就是本題的答案。
主要思路:因為有了冷凍期,所以每個位置的狀態有如下三種:
定義三個數組,分別表示i位置這三種情況下的最大值是多少
顯然有如下結論:
針對一個普遍位置i
最大收益就是如上三種方式的最大值。完整代碼見:
由於三個數組有遞推關系,所以可以用三個變數替換三個數組,做空間壓縮,優化後的代碼如下:
主要思路:由於沒有冷凍期,所以在i位置的時候,狀態只有兩種
針對0位置
針對普遍位置i
完整代碼如下:
同樣的,兩個數組都有遞推關系,可以做空間壓縮,簡化後的代碼如下:
原文鏈接:買賣股票的最佳時機系列問題 - Grey Zeng - 博客園
⑥ 編程怎麼才能讓自己有思路呢
其實很簡單
首先明白你要寫一個什麼東西【比如你要寫一個登陸的程序】
然後分析你這個程序要那些步驟來完成 【以登陸舉例】
(1)登陸頁面寫好
(2)分析基礎元素有登陸賬號,登陸密碼,為了安全會有驗證碼 然後提交登陸
(3)這里就說登陸程序了 你把這些參數提交到後台,你的程序就開始了:
【1】驗證驗證是否正確
【2】驗證賬號是否存在
【3】驗證賬號密碼是否正確
【4】驗證通過記錄session你這個登陸信息
通過基本分析你得到了這個程序大概要寫哪些步驟 當然我寫的是簡單的例子分析,如果要更安全肯定還有一些操作
把你這些步驟以注釋形式寫道你的編程內,按照你的思路步驟來逐步編寫
編寫完成可以考慮下你的思路是否可以精簡步驟,滿滿磨練就好了
⑦ 程序員都應該精通的六種演算法,你會了嗎
對於一名優秀的程序員來說,面對一個項目的需求的時候,一定會在腦海里浮現出最適合解決這個問題的方法是什麼,選對了演算法,就會起到事半功倍的效果,反之,則可能會使程序運行效率低下,還容易出bug。因此,熟悉掌握常用的演算法,是對於一個優秀程序員最基本的要求。
那麼,常用的演算法都有哪些呢?一般來講,在我們日常工作中涉及到的演算法,通常分為以下幾個類型:分治、貪心、迭代、枚舉、回溯、動態規劃。下面我們來一一介紹這幾種演算法。
一、分治演算法
分治演算法,顧名思義,是將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
分治演算法一般分為三個部分:分解問題、解決問題、合並解。
分治演算法適用於那些問題的規模縮小到一定程度就可以解決、並且各子問題之間相互獨立,求出來的解可以合並為該問題的解的情況。
典型例子比如求解一個無序數組中的最大值,即可以採用分治演算法,示例如下:
def pidAndConquer(arr,leftIndex,rightIndex):
if(rightIndex==leftIndex+1 || rightIndex==leftIndex){
return Math.max(arr[leftIndex],arr[rightIndex]);
}
int mid=(leftIndex+rightIndex)/2;
int leftMax=pidAndConquer(arr,leftIndex,mid);
int rightMax=pidAndConquer(arr,mid,rightIndex);
return Math.max(leftMax,rightMax);
二、貪心演算法
貪心演算法是指在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的僅是在某種意義上的局部最優解。
貪心演算法的基本思路是把問題分成若干個子問題,然後對每個子問題求解,得到子問題的局部最優解,最後再把子問題的最優解合並成原問題的一個解。這里要注意一點就是貪心演算法得到的不一定是全局最優解。這一缺陷導致了貪心演算法的適用范圍較少,更大的用途在於平衡演算法效率和最終結果應用,類似於:反正就走這么多步,肯定給你一個值,至於是不是最優的,那我就管不了了。就好像去菜市場買幾樣菜,可以經過反復比價之後再買,或者是看到有賣的不管三七二十一先買了,總之最終結果是菜能買回來,但搞不好多花了幾塊錢。
典型例子比如部分背包問題:有n個物體,第i個物體的重量為Wi,價值為Vi,在總重量不超過C的情況下讓總價值盡量高。每一個物體可以只取走一部分,價值和重量按比例計算。
貪心策略就是,每次都先拿性價比高的,判斷不超過C。
三、迭代演算法
迭代法也稱輾轉法,是一種不斷用變數的舊值遞推新值的過程。迭代演算法是用計算機解決問題的一種基本方法,它利用計算機運算速度快、適合做重復性操作的特點,讓計算機對一組指令(或一定步驟)進行重復執行,在每次執行這組指令(或這些步驟)時,都從變數的原值推出它的一個新值。最終得到問題的結果。
迭代演算法適用於那些每步輸入參數變數一定,前值可以作為下一步輸入參數的問題。
典型例子比如說,用迭代演算法計算斐波那契數列。
四、枚舉演算法
枚舉演算法是我們在日常中使用到的最多的一個演算法,它的核心思想就是:枚舉所有的可能。枚舉法的本質就是從所有候選答案中去搜索正確地解。
枚舉演算法適用於候選答案數量一定的情況。
典型例子包括雞錢問題,有公雞5,母雞3,三小雞1,求m錢n雞的所有可能解。可以採用一個三重循環將所有情況枚舉出來。代碼如下:
五、回溯演算法
回溯演算法是一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就「回溯」返回,嘗試別的路徑。
許多復雜的,規模較大的問題都可以使用回溯法,有「通用解題方法」的美稱。
典型例子是8皇後演算法。在8 8格的國際象棋上擺放八個皇後,使其不能互相攻擊,即任意兩個皇後都不能處於同一行、同一列或同一斜線上,問一共有多少種擺法。
回溯法是求解皇後問題最經典的方法。演算法的思想在於如果一個皇後選定了位置,那麼下一個皇後的位置便被限制住了,下一個皇後需要一直找直到找到安全位置,如果沒有找到,那麼便要回溯到上一個皇後,那麼上一個皇後的位置就要改變,這樣一直遞歸直到所有的情況都被舉出。
六、動態規劃演算法
動態規劃過程是:每次決策依賴於當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱為動態規劃。
動態規劃演算法適用於當某階段狀態給定以後,在這階段以後的過程的發展不受這段以前各段狀態的影響,即無後效性的問題。
典型例子比如說背包問題,給定背包容量及物品重量和價值,要求背包裝的物品價值最大。
⑧ 編程好的思路。
我認為編程,重要的不是如何華麗的代碼,而是能夠將用戶需求轉化為機器語言的能力
你的很多思想,是剛開始做程序員的普遍想法,開始思考通過模塊化設計能夠更省力,更快捷的完成工作,程序運行效率還要高。
如果你在大軟體公司工作過,就不會有這種困惑了。因為對於具有一定規模的軟體公司,已經在相當的時間內積累起很豐富的模塊和庫資源,程序員們只需要根據項目的不同象選擇自助餐一樣給拼接到一起,就有了基本框架。
最重要的還是做好用戶需求到需求說明,再到系統框架設計這個工作,會少走很多彎路。
細化到編寫程序,我覺得很重要的一點就是要求公司裡面的程序員要有絕對規范的編程習慣,不然在團隊協作的時候會出很多問題,做出來的基礎庫也經不起時間的考驗。
還有就是你說的模塊化的東西不是萬能的,和你經常從事的項目領域密切相關,你用著很順手,別人可能用不了。比如你是做信息系統的,那麼一個好的查詢分析模塊很多地方都能用,用戶信息管理就要根據復雜程度做幾套,比如能夠定期更換密碼的,比如許可權是要細化到列的,比如只是一個簡單的用戶密碼。根據項目的不同選用。
有些人鼓吹自動化編程,利用商業化的系統模板進行配置。我認為對於企業應用還是可以的,但是對於軟體開發就不可取了。因為提供模板的單位水平如何你並不知道,裡面是否存在大量bug你也不清楚,只是演示做的漂亮。一旦你用了這個東西,在你的項目中出現問題,你debug是查不到具體原因的,苦果只能自己吃,這是個建議,有點離題,但是怕你思路到了一定程度就推崇這種方法。
最後一點,大部分的項目都是需要資料庫作為後台支持的,一定要注意處理好資料庫設計的問題,不然很容易因為庫設計的不合理造成程序復雜,或者是在使用一段時間後效率嚴重降低,造成程序重新返工,就說這么多,希望你能有所收獲