覆盤PHP經典問題解決過程 窮舉問題

2021-09-19 22:38:24 字數 3177 閱讀 3922

對於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 ...