對於5個數字的集合[1,2,3,4,5],從中取出3個,不分先後,共有多少種取法?
結果是有10種取法,那麼新的問題來了,請問分別是哪10種取法?
你可能會說這是個很簡單的問題,答案脫口而出,[1,2,3]、[1,2,4]、[1,2,5]、[2,3,4]...
但是當我們需要用程式複製這個思考過程,或者說分解人們是如何進行窮舉的思維時,你會發現這並不簡單!
只要成功實現了這一過程,我們就可以把問題推廣到,5個中取2個、5個中取4個、6個中取3個等等
在解決多規格商品查詢的問題時,這個演算法是可行的解決方案之一一般情況是怎樣的,比如5取2:
控制1,在[2,3,4,5]中尋找另乙個數,得到4組
放棄1,控制2,在[3,4,5]中尋找另乙個數,得到3組
放棄[1,2],控制3,在[4,5]中尋找另乙個數,得到2組
放棄[1,2,3],控制4,只剩下5乙個數可選了,得到1組,結束窮舉,得到10組
沒有感覺,再看乙個,比如5取3:
控制[1,2],在[3,4,5]中尋找另乙個數,直到末尾,得到3組
控制[1,3],在[4,5]中尋找另乙個數,直到末尾,得到2組
控制[1,4],只剩下5乙個數可選了,得到1組
放棄1,控制[2,3],在[4,5]中尋找另乙個數,直到末尾,得到2組
放棄1,控制[2,4],只剩下5乙個數可選了,得到1組
放棄1、2,控制[3,4],只剩下5乙個數可選了,得到1組,結束窮舉,總共10組
你可能覺得有感覺了,再來,比如看5取4:
控制[1,2,3],在[4,5]中尋找另乙個數,得到兩組
控制[1,2,4],只剩下乙個5可選,得到一組
控制[1,3,4],只剩下乙個5可選,得到一組
放棄1,控制[2,3,4],只剩下乙個5可選,得到一組,結束窮舉,總共5組
我們可以嘗試著發現以下結論(也許存在無用的結論):
控制的個數=要取出的個數-1
當只剩下乙個數可選時,意味著要更換控制的數
當控制的數改變到最左側時,意味著要放棄乙個數
當【放棄的個數+要取出的個數=總個數】時,意味著窮舉結束
程式方面,我們可以聯想到,輸入函式的引數應該只有兩個:
等待窮舉的陣列
需要取出的個數
返回值就是乙個二維陣列,每組數代表一種組合。
可是,到了這裡好像問題還是毫無頭緒。
我們再回去仔細觀察5取3時候的控制數,它的控制數其實是,除了5之外的4個數進行了一次4取2的結果。
那4取2的控制數呢,分析後發現,其實就是3取1的結果。
所以,當我們在5取3時,其實可以看做先做3取1,再用3取1的結果做4取2,再用4取2的結果做5取3。
換一種思路,我們要求10取4的窮舉時,就得先求9取3,進而得先求8取2,最後落到7取1。再從7取1的結果推出,8取2的結果,進而推出9取3,最後得到10取4的解。
可以總結為,將任何窮舉問題首先化簡到 n 取1,再層層推出上級的結果。
其實,看到這個結論,就明白要用遞迴了,但是沒有奧數大神思維的我們還是一步一步來。
為什麼一定要化簡到 n 取1的問題呢,那是因為程式中的迴圈只會取1。
從最簡單的開始,我們嘗試寫乙個 n 取1的函式:
function one($count)
return $rst;
}//執行one(3)輸出 [[1],[2],[3]]
我們通過上面的思路嘗試寫乙個 n 取2的函式:
function two($count)
}return $result;
}//執行 two(4) 輸出[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
我們把這種情況擴充套件到 n 取3:
function three($count)
}return $result;
}//執行 three(5) 輸出的結果和人為窮舉相同
那要如何通過遞迴把這三種情況擴充套件呢,我們作如下分析(需要較強的程式設計基礎):
我們必須也用變數代表要取出的數量,也就是 n 取 m,所以輸入的引數就是 n 和 m
我們要以 p 取1的結果作為基礎推出上層結果,所以遞迴深入的邊際條件就是,m-遞迴次數=1
我們每次向上層返回的結果,取出的個數並不固定,所以也必須用變數表示下標,以此來組合新的結果(這是乙個觀察結論)
php經典面試題:窮舉問題
觀察結論
所以我們的遞迴函式就是:
function getanswer($amount, $need)
return $rst;
}else
}return $result;
}}//測試了幾種常見情況,返回結果均正確
我們現在有了獲取窮舉陣列下標的方法,回到最開始的問題
我們需要輸入函式的引數應該是:
等待窮舉的陣列
需要取出的個數
所以最終的函式:
function getfinallyanswer($array, $pick)
}return $rst;
}//getfinallyanswer([7,8,9,10], 3)
//我們可以嘗試一下從[7,8,9,10]中任取3個,結果完全正確
當我寫完這篇文章時,我上網查了一下,網上的寫法和我的差別是非常大的,可以說基本看不懂其他人的思路。
所以,我認為這個演算法肯定是存在優化的空間的,可能存在更加巧妙的方法,歡迎討論。
另外,你可能會想,窮舉排列(分先後順序)的演算法會不會比這個更複雜,但其實比這個要簡單的多。可以嘗試想一下,很快就能想出來。
那麼這個演算法在多規格商品檢索中到底有什麼用呢,嗯,這個題目又可以開乙個新坑了。
U盤中毒問題解決
背景 最近在學校的列印店裡列印東西,結果過了一段時間再使用的時候發現,u盤中的資料夾都成了快捷方式,只有乙個pdf檔案是好的,無奈,其中有比較重要的東西,所以尋求解決辦法,最終解決,為方便以後查閱,遂記錄之。表現 所有的檔案都成了快捷方式,這種病毒屬於資料夾快捷方式中毒,又稱1kb快捷方式中毒,所以...
PHP跨域問題解決
前後端分離,最常見的問題就是跨域,在前端裡面,解決跨域的時候總顯得那麼的奇怪,什麼jsonp啊,ajax啊,cors啊什麼的,總覺得是在鑽空子進行跨域,其實在php檔案裡面只需要加一段 就可以跨域了,前端你該怎麼寫還是怎麼寫,post,get隨便用 一 直接在php檔案裡新增允許跨域訪問,當然,這是...
php 亂碼 問題解決辦法
php亂碼問題解決辦法 必須使使用的 資料庫 文字編輯 瀏覽器 資料獲取 編碼格式一致。如設定成 utf 8的方法為 1.資料庫建立時設定 字符集為utf 8 2.在專案屬性 或檔案屬性 文字檔案編碼處設定成utf 8 如果沒用ide工具編寫,可以不設定此項 3.設定網頁顯示編碼格式 header ...