日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

五大常用算法

發(fā)布時(shí)間:2023/12/10 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 五大常用算法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

學(xué)習(xí)算法前,先了解一下五大常用算法,方便后續(xù)歸類總結(jié)及練習(xí),到達(dá)觸類旁通的效果。

一。分治算法:快速排序、歸并排序、大整數(shù)乘法、二分查找、遞歸(漢諾塔)

基本概念:把一個(gè)復(fù)雜的問題分成若干個(gè)相同或相似的子問題,再把子問題分成更小的子問題… , 知道最后子問題可以簡(jiǎn)單的直接求解,原問題的解即子問題的解的合并。
看上去有點(diǎn)類似Fork/Join框架,或map-reduce。

排序算法中的快速排序、歸并排序都是使用的分治算法。

分治算法的適用場(chǎng)景:
1)當(dāng)問題規(guī)模縮小到一定的程度就可以很容易解決
2)該問題可以分解為若干個(gè)規(guī)模較小的相同問題
3)該問題分解出的若干子問題的解可以合并為該問題的解
4)每個(gè)子問題都是獨(dú)立的,相互之間沒有交集。

使用分治法的經(jīng)典場(chǎng)景:
1)二分搜索
2)大整數(shù)乘法
3)合并排序
4)快速排序
5)漢諾塔

分治算法經(jīng)典例題:
輸入一組整數(shù),求出這組數(shù)字子序列和中最大值。也就是求出最大子序列的和,不必求出最大的那個(gè)序列。例如:序列:-2, 11, -1, 13, -5, -2 , 則最大子序列的和為20。

public static void main(String[] args) {int[] a = { -2, 11, -4, 13, -5, -2 };// 最大子序列和為20int[] b = { -6, 2, 4, -7, 5, 3, 2, -1, 6, -9, 10, -2 };// 最大子序列和為16System.out.println(maxSubSum1(a));System.out.println(maxSubSum4(b)); }// 最大子序列求和算法一 public static int maxSubSum1(int[] a) {int maxSum = 0;// 從第i個(gè)開始找最大子序列和for (int i = 0; i < a.length; i++) {// 找第i到j(luò)的最大子序列和for (int j = i; j < a.length; j++) {int thisSum = 0;// 計(jì)算從第i個(gè)開始,到第j個(gè)的和thisSumfor (int k = i; k <= j; k++) {thisSum += a[k];}// 如果第i到第j個(gè)的和小于thisSum,則將thisSum賦值給maxSumif (thisSum > maxSum) {maxSum = thisSum;}}}return maxSum; }// 時(shí)間復(fù)雜度O(n的平方) public static int maxSubSum2(int[] a) {int maxSum = 0;for (int i = 0; i < a.length; i++) {// 將sumMax放在for循環(huán)外面,避免j的變化引起i到j(luò)的和sumMax要用for循環(huán)重新計(jì)算int sumMax = 0;for (int j = i; j < a.length; j++) {sumMax += a[j];if (sumMax > maxSum) {maxSum = sumMax;}}}return maxSum; }// 遞歸,分治策略 // 2分logn,for循環(huán)n,時(shí)間復(fù)雜度O(nlogn) public static int maxSubSum3(int[] a) {return maxSumRec(a, 0, a.length - 1); }public static int maxSumRec(int[] a, int left, int right) {// 遞歸中的基本情況if (left == right) {if (a[left] > 0)return a[left];elsereturn 0;}int center = (left + right) / 2;// 最大子序列在左側(cè)int maxLeftSum = maxSumRec(a, left, center);// 最大子序列在右側(cè)int maxRightSum = maxSumRec(a, center + 1, right);// 最大子序列在中間(左邊靠近中間的最大子序列+右邊靠近中間的最大子序列)int maxLeftBorderSum = 0, leftBorderSum = 0;for (int i = center; i >= left; i--) {leftBorderSum += a[i];if (leftBorderSum > maxLeftBorderSum)maxLeftBorderSum = leftBorderSum;}int maxRightBorderSum = 0, rightBorderSum = 0;for (int i = center + 1; i <= right; i++) {rightBorderSum += a[i];if (rightBorderSum > maxRightBorderSum)maxRightBorderSum = rightBorderSum;}// 返回最大子序列在左側(cè),在右側(cè),在中間求出的值中的最大的return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum); }public static int max3(int a, int b, int c) {return a > b ? (a > c ? a : c) : (b > c ? b : c); }// 時(shí)間復(fù)雜度:O(n); 任何a[i]為負(fù)時(shí),均不可能作為最大子序列前綴;任何負(fù)的子序列不可能是最有子序列的前綴 public static int maxSubSum4(int[] a) {int maxSum = 0, thisSum = 0;for (int j = 0; j < a.length; j++) {thisSum += a[j];if (thisSum > maxSum)maxSum = thisSum;else if (thisSum < 0)thisSum = 0;}return maxSum; }



二。動(dòng)態(tài)規(guī)劃算法

基本概念:將待求解的問題分解為若干個(gè)子問題,按順序求解子問題,前一問題的解,為后一問題的求解提供有用的信息。在求解任一子問題時(shí),列出各種可能的局部解,通過(guò)決策保留那些有可能達(dá)到最優(yōu)的局部解,丟棄其他局部解。依次解決各種子問題,最后一個(gè)子問題就是初始問題的解。
由于動(dòng)態(tài)規(guī)劃算法解決的問題是有重疊的子問題,為了減少重復(fù)計(jì)算,對(duì)每一個(gè)子問題只解一次,將其不同階段的不同狀態(tài)保存在一個(gè)二維數(shù)組中。
動(dòng)態(tài)規(guī)劃算法以分治算法類似,不同在于:適合于動(dòng)態(tài)規(guī)劃算法求解的問題,經(jīng)分解后得到的子問題,往往不是互相獨(dú)立的,而是下一個(gè)子階段的求解是建立在上一個(gè)子階段的解的基礎(chǔ)上,進(jìn)行進(jìn)一步求解的。

動(dòng)態(tài)規(guī)劃的適用場(chǎng)景
1)最優(yōu)化原理:該問題的最優(yōu)解所包含的子問題的解也是最優(yōu)的。
2)無(wú)后效性:某階段狀態(tài)一旦確定,就不受這個(gè)狀態(tài)以后決策的影響。即某狀態(tài)以后的過(guò)程不會(huì)影響以前的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。
3)有重疊子問題:即子問題之間不相互獨(dú)立,一個(gè)子問題的解在下一階段決策中可能被多次使用到。

經(jīng)典問題:
給定兩個(gè)字符串str1和str2,返回兩個(gè)字符串的最長(zhǎng)公共子序列,例如:str1=“1A2C3D4B56",str2=“B1D23CA45B6A”,"123456"和"12C4B6"都是最長(zhǎng)公共子序列,返回哪一個(gè)都行。

分析:這事經(jīng)典的動(dòng)態(tài)規(guī)劃問題,假設(shè)str1的長(zhǎng)度為M, str2的長(zhǎng)度為N, 則生成M*N的二維數(shù)組dp, dp[i][j]的含義是str1[0…i]與str2[0…j]的最長(zhǎng)公共子序列的長(zhǎng)度。

dp值的求法如下:
dp[i][j]的值比如和dp[i-1][j], dp[i][j-1]相關(guān),結(jié)合下面的代碼來(lái)看,實(shí)際上從第一行和第一列開始計(jì)算的,

public static void main(String[] args) {String A = "1A2C3D4B56";String B = "B1D23CA45B6A";System.out.println(findLCS(A, A.length(), B, B.length())); }public static int findLCS(String A, int Alen, String B, int Blen) {int dp[][] = new int[Alen+1][Blen+1];for (int i = 0; i < Alen; i++) {for (int j = 0; j < Blen; j++) {if (A.charAt(i) == B.charAt(j)) {dp[i + 1][j + 1] = dp[i][j] + 1;} else {dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]);}}}return dp[Alen][Blen]; }



三。貪心算法

貪心算法是通過(guò)局部最優(yōu)解來(lái)達(dá)到全局最優(yōu)解。

下面是一個(gè)可以試用貪心算法解的題目,貪心解的確不錯(cuò),可惜不是最優(yōu)解。

[背包問題]有一個(gè)背包,背包容量是M=150。有7個(gè)物品,物品可以分割成任意大小。

要求盡可能讓裝入背包中的物品總價(jià)值最大,但不能超過(guò)總?cè)萘俊?/p>

物品 A B C D E F G

重量 35 30 60 50 40 10 25

價(jià)值 10 40 30 50 35 40 30

分析:
目標(biāo)函數(shù): ∑pi最大

約束條件是裝入的物品總重量不超過(guò)背包容量,即∑wi<=M( M=150)
1)根據(jù)貪心的策略,每次挑選價(jià)值最大的物品裝入背包,得到的結(jié)果是否最優(yōu)呢?
2)每次挑選重量最小的物品裝入背包,是否能得到最優(yōu)解?
3)每次選取單位重量?jī)r(jià)值最大的物品,成為解本地的策略?

貪心算法簡(jiǎn)單易行,但貪心算法需要證明后才能真正運(yùn)用到算法中。一般來(lái)說(shuō),貪心算法的證明圍繞著整個(gè)問題的最優(yōu)解一定由在貪心策略中存在的子問題的最優(yōu)解得來(lái)的。

對(duì)于本題的三種貪心策略,都無(wú)法成立,即無(wú)法被證明。解釋如下:

1)選取價(jià)值最大者。
反例:W=30
物品:A B C
重量:28 12 12
價(jià)值:30 20 20

根據(jù)策略,選A, 但選BC最合適

2)選取重量最小,反例與上述類似

3)選取單位重量?jī)r(jià)值最大的物品。反例:
W=30
物品:A B C
重量:28 20 10
價(jià)值:28 20 10

根據(jù)策略,三種物品單位重量?jī)r(jià)值一樣,程序無(wú)法依據(jù)現(xiàn)有策略作出判斷,如果選擇A,則答案錯(cuò)誤。

2)貪心算法的經(jīng)典案例:
設(shè)有n個(gè)正整數(shù),將他們連成一排,組成一個(gè)最大的多位整數(shù)。
例如:n=3時(shí),3個(gè)整數(shù)13,312,343,連成的最大整數(shù)為34331213。
又如:n=4時(shí),4個(gè)整數(shù)7,13,4,246,連成的最大整數(shù)為7424613。

要求輸入:n, N個(gè)數(shù)
輸出:連成的多位數(shù)

算法分析:該題很容易想到貪心法,但解題時(shí)很多人把整數(shù)按從大到小的順序連接起來(lái),測(cè)試題目的例子也都符合,但結(jié)果不對(duì)。例如:我們很容易找到12, 121應(yīng)該組成12121而非12112, 但如12, 123呢,就是12312,而不是12123。所以,通過(guò)整數(shù)排序的方法是不對(duì)的。

結(jié)論:該題可以用貪心算法,只是剛才采用的貪心策略不對(duì)。正確的貪心算法的標(biāo)準(zhǔn)是:先把整數(shù)轉(zhuǎn)成字符串,然后再比較a+b和b+a, 如果a+b >= b+a, 就把a(bǔ)排在b前面, 反之把a(bǔ)排在b后面。

四。回溯算法

基本概念:回溯算法是一個(gè)類似枚舉的搜索嘗試過(guò)程,主要在搜索嘗試過(guò)程中尋找問題的解,當(dāng)發(fā)現(xiàn)已不滿足求解條件時(shí),就“回溯”返回,嘗試別的路徑。深度優(yōu)先。
回溯算法是一種選優(yōu)搜索法,按選優(yōu)條件向前搜索,以達(dá)到目標(biāo)。當(dāng)搜索到某一步時(shí),發(fā)現(xiàn)原先選擇并不優(yōu)或達(dá)不到目標(biāo),就退回一步重新選擇,這種走不通就退回再走的技術(shù)成為回溯法,而滿足回溯條件的某個(gè)狀態(tài)的點(diǎn)成為“回溯點(diǎn)”。

對(duì)于回溯算法的簡(jiǎn)單描述是:把問題的解空間轉(zhuǎn)化為圖或樹的結(jié)構(gòu),然后使用深度優(yōu)先進(jìn)行遍歷,遍歷過(guò)程中尋找所有可行解,從而找到最優(yōu)解。

其基本思想類似于:圖的深度優(yōu)先搜索;二叉樹的后序遍歷。

回溯法的詳細(xì)描述為:回溯法按深度優(yōu)先搜索解空間樹。首先從根節(jié)點(diǎn)出發(fā),當(dāng)搜索到解空間數(shù)的某一節(jié)點(diǎn)時(shí),先利用剪枝函數(shù)判斷該節(jié)點(diǎn)是否可行(即能得到問題的解)。如果不可行,則跳過(guò)對(duì)該節(jié)點(diǎn)為根的子樹的搜索,逐層向其祖先節(jié)點(diǎn)回溯;否則,進(jìn)入該子樹,繼續(xù)按深度優(yōu)先策略搜索。
2. 回溯算法的實(shí)現(xiàn):遞歸和迭代

回溯算法的經(jīng)典問題:0-1背包問題
有n種物品和一個(gè)背包,第i種物品的重量是wi,其價(jià)值為pi,背包的容量為c. 問:怎樣把物品裝入背包,背包中的物品的總價(jià)值最大。

分析:從n種物品中選擇部分物品,這樣的題目解空間是子集樹。例如,當(dāng)物品的種類數(shù)為3是,其解空間如下圖:

邊1表示選擇該物品,邊0表示不選擇該物品。這樣,這個(gè)樹從根節(jié)點(diǎn)到葉子節(jié)點(diǎn),包含了把物品放入背包的所有可能性。
回溯搜索過(guò)程,如果來(lái)到了葉子節(jié)點(diǎn),表示一條搜索路徑結(jié)束,如果該路徑上存在更優(yōu)的解,則保存下來(lái),如果不是葉子節(jié)點(diǎn),是中間的節(jié)點(diǎn)(如B), 就遍歷其子節(jié)點(diǎn)(D和E), 如果子節(jié)點(diǎn)滿足剪枝條件,就繼續(xù)回溯搜索子節(jié)點(diǎn)。

五。分支限界算法

基本概念
類似于回溯法,也是一種在問題的解空間樹T上搜索問題解的算法。但在一般情況下,分支限界法與回溯法的求解目標(biāo)不同回溯法的求解目標(biāo)是找出解空間樹中滿足約束條件的所有解,而分支限界法的求解目標(biāo)則是滿足約束條件的一個(gè)解,或是從滿足約束條件的解中找出使某一目標(biāo)函數(shù)值達(dá)到極大或極小的解,即在某種意義下的最優(yōu)解。

分支限界法的基本思想是對(duì)有約束條件的最優(yōu)化問題的所有可行解(數(shù)目有限)空間進(jìn)行搜索。該算法在具體執(zhí)行時(shí),把全部可行的解空間不斷分割為越來(lái)越小的自己(成為分支),并為每個(gè)自己內(nèi)的解的值計(jì)算一個(gè)下界或上界(成為界定)。

在每次分支后,對(duì)凡是界限超出已知可行解值的那些子集不再做進(jìn)一步分支。這樣,解的許多子集(即搜索樹上的許多節(jié)點(diǎn))就可以不必考慮了,從而縮小了搜索范圍。這一過(guò)程一直進(jìn)行到找出可行解為止,該可行解的值不大于任務(wù)子集的界限,因此這種算法一般可以求得最優(yōu)解。

將問題分支為子問題,并對(duì)這些子問題定界的步驟稱為分支定界法。

知識(shí)附錄:深度優(yōu)先搜索和廣度優(yōu)先搜索

1)廣度優(yōu)先搜索:使用隊(duì)列的先進(jìn)先出

2)深度優(yōu)先搜索:

2. 分支限界法的經(jīng)典問題:旅行售貨員問題

1)問題描述:某售貨員要到若干城市去賣商品,已知各城市之間的路程。他要選定一條從駐地出發(fā),經(jīng)過(guò)每個(gè)城市一次,最后回到駐地的路線,使總的路程最小。

下圖為1,2,3,4 四個(gè)城市及路線圖,任意兩個(gè)城市之間不一定都有路可達(dá)。

2)問題理解:
分支限界法利用:廣度優(yōu)先搜索和最優(yōu)值策略
利用二位數(shù)組保存圖信息,一旦一個(gè)城市沒有通向另外城市的路,則不可能有回路,不用再找下去了。
我們?nèi)我膺x擇一個(gè)城市,作為出發(fā)點(diǎn)(因?yàn)樽詈蠖际且粋€(gè)回路,從哪出發(fā)都一樣)

3)關(guān)鍵思路:
想象一下,我們就是旅行員,從城市1出發(fā),根據(jù)廣度優(yōu)先搜索的思路,我們要把從城市1能到達(dá)的下一個(gè)城市,都要作為一種路徑走一下試試。可在程序里面怎樣實(shí)現(xiàn)這種“試試”呢?

答案是:可以利用一種數(shù)據(jù)結(jié)構(gòu),保存我們每走一步后,當(dāng)前的一些狀態(tài)參數(shù)。比如,我們已經(jīng)走過(guò)的城市數(shù)目(這樣就知道,我們有沒有走完,比如上圖,當(dāng)我們走了四個(gè)城市之后,無(wú)論從第四個(gè)城市是否能回到起點(diǎn)城市,都意味著我們走完了,只是這條路徑合不合約束以及能不能得到最優(yōu)解的問題)。我們把這種保存狀態(tài)參數(shù)的數(shù)據(jù)結(jié)構(gòu)定義成Node。需要另一個(gè)數(shù)據(jù)結(jié)構(gòu)用來(lái)保存我們每次試出來(lái)的路徑,這就是MiniHeap

Node{
int s; //結(jié)點(diǎn)深度,即當(dāng)前走過(guò)了幾個(gè)城市
int x[MAX_SIZE]; //保存走到這個(gè)結(jié)點(diǎn)時(shí)的路徑信息
}
MiniHeap{
//保存所有結(jié)點(diǎn)并提供一些結(jié)點(diǎn)的操作
}
————————————————
版權(quán)聲明:本文為CSDN博主「Shi Peng」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/shijinghan1126/article/details/87951372

總結(jié)

以上是生活随笔為你收集整理的五大常用算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。