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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

回溯java算法_聊聊算法——回溯算法

發(fā)布時間:2025/3/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 回溯java算法_聊聊算法——回溯算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

“遞歸只應(yīng)天上有,迭代還須在人間”,從這句話我們可以看出遞歸的精妙,確實厲害,遞歸是將問題規(guī)模逐漸減小,

然后再反推回去,但本質(zhì)上是從最小的規(guī)模開始,直到目標(biāo)值,思想就是數(shù)學(xué)歸納法,舉個例子,求階乘 N!=(N-1)!*N ,

而迭代是數(shù)學(xué)中的極限思想,利用前次的結(jié)果,逐漸靠近目標(biāo)值,迭代的過程中規(guī)模不變,舉例如For循環(huán),直到終止條件。

遞歸的思想不復(fù)雜,但代碼理解就麻煩了,要理解一個斐波那契數(shù)組遞歸也不難,比如下面的回溯算法遞歸,for 循環(huán)里面

帶遞歸,看代碼是不是暈了?好,下面我們專門來聊聊這個框架!

作者原創(chuàng)文章,謝絕一切形式轉(zhuǎn)載,違者必究!

準(zhǔn)備:

Idea2019.03/JDK11.0.4

難度: 新手--戰(zhàn)士--老兵--大師

目標(biāo):

回溯算法分析與應(yīng)用

1 回溯算法

先給出個回溯算法框架:

backtrack(路徑,選擇列表){

//結(jié)束條件

將中間結(jié)果加入結(jié)果集

for 選擇 in 選擇列表:

//做選擇,并將該選擇從選擇列表中移除

路徑.add(選擇)

backtrack(路徑,選擇列表)

//撤銷選擇

路徑.remove(選擇)

}

為了理解上述算法,回想一下,我前篇文章中有說到,多路樹的遍歷算法框架:

private static class Node {

public int value;

public Node[] children;

}

public static void dfs(Node root){

if (root == null){

return;

}

// 前序遍歷位置,對node做點事情

for (Node child:children

) {

dfs(child);

}

// 后序遍歷位置,對node做點事情

}

如果去掉路徑增加/撤銷的邏輯,是不是和多路樹的遍歷算法框架一樣了呢?其實就是一個多路樹DFS的變種算法!

另外,雖然遞歸代碼的理解難度大,運行時是棧實現(xiàn),但看官不要掉進(jìn)了遞歸棧,否則就出不來了,如果試著用打斷

點逐行跟進(jìn)的辦法非要死磕,那對不起,估計三頓飯功夫也可能出不來,甚至我懷疑起自己的智商來,所以,理解遞歸,

核心就是抓住函數(shù)體來看,抽象的理解,只看懂 N 和 N-1 的轉(zhuǎn)移邏輯即可!不懂的先套用再說,也不定哪天就靈感來了,

一下頓悟!

那就先上菜了!先是經(jīng)典回溯算法,代號A,我們要做個數(shù)組全排列,我看別人說回溯算法也都是拿這個例子說事,

我就落個俗套:

class Permutation {

// 排列組合算法

private static List> output = new LinkedList();

static List> permute( List nums, // 待排列數(shù)組

int start //起始位置

){

if (start == nums.size()){

output.add(new ArrayList<>(nums));

}

for (int i = start; i < nums.size(); i++) {

// 做選擇,交換元素位置

Collections.swap(nums, start, i);

// 遞歸,縮小規(guī)模

permute( nums,start +1);

// 撤銷選擇,回溯,即恢復(fù)到原狀態(tài),

Collections.swap(nums, start, i);

}

return output;

}

// 測試

public static void main(String[] args) {

List nums = Arrays.asList(1,2,3,4);

List> lists = permute(nums,0);

lists.forEach(System.out::println);

}

}

代碼理解:數(shù)組 {1,2,3} 的全排列,我們馬上知道有{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}排列,具體過程就是通過遞歸縮小規(guī)模,

做 {1,2,3} 排列,先做 {2,3} 排列,前面在加上 1 即可,繼續(xù)縮小,就是做 {3} 的排列。排列就是同一個位置把所有不同的數(shù)都放一次,

那么代碼實現(xiàn)上可使用交換元素法,比如首個位置和所有元素都交換一遍,不就是全部可能了嗎。這樣,首個位置所有可能就遍歷了

一遍,然后在遞歸完后,恢復(fù)(回溯)一下,就是說每次交換都是某一個下標(biāo)位置,去交換其他所有元素。

再來個全排列的算法實現(xiàn),代號B,也是使用回溯的思想:

public class Backtrack {

public static void main(String[] args) {

int[] nums = {1,2,3,4};

List track = new LinkedList<>();

List> res = backtrack(nums,track);

System.out.println(res);

}

// 存儲最終結(jié)果

private static List> result = new LinkedList<>();

// 路徑:記錄在 track 中

// 選擇列表:nums 中不存在于 track 的那些元素

// 結(jié)束條件:nums 中的元素全都在 track 中出現(xiàn)

private static List> backtrack(int[] nums,List track){

// 結(jié)束條件

if (track.size() == nums.length){

result.add(new LinkedList<>(track));

return null;

}

for (int i = 0; i < nums.length; i++) {

if (track.contains(nums[i]))

continue;

// 做選擇

track.add(nums[i]);

backtrack(nums,track);

// 撤銷選擇

track.remove(track.size()-1);

}

return result;

}

}

代碼解析:對 {1,2,3} 做全排列,先將 List[0] 放入鏈表,如果鏈表中存在該元素,就忽略繼續(xù),繼續(xù)放入List[0+1],同樣的,

存在即忽略繼續(xù),直到將List中所有元素,無重復(fù)的放入鏈表,這樣就完成了一次排列。這個算法的技巧,是利用了鏈表的

有序性,第一個位置會因為回溯而嘗試放入所有的元素,同樣,第二個位置也會嘗試放入所有的元素。

畫出個決策樹:

以 {1-3-2} 為例,如果鏈表第一個位置為1,那第二個位置為 {2,3} 之一,{1}由于屬于存在的重復(fù)值忽略,

如果第二個位置放了{(lán)3},那第三個位置就是{2},就得出了一個結(jié)果。

我們對比一下以上兩個算法實現(xiàn): 特別注意,算法B是真正的遞歸嗎?有沒有縮小計算規(guī)模?

時間復(fù)雜度計算公式:分支個數(shù) * 每個分支的計算時間

算法A的分支計算只有元素交換,按Arraylist處理,視為O(1),算法B分支計算包含鏈表查找為O(N),

算法A:N!* O(1) ,階乘級別,耗時不送。

算法B:N^n * O(N) ,指數(shù)級別,會爆炸!

我使用10個數(shù)全排測試如下(嚴(yán)謹(jǐn)?shù)闹v,兩者有數(shù)據(jù)結(jié)構(gòu)不同的影響,并不是說僅有算法上的差異):

總結(jié):回溯和遞歸是兩種思想,可以融合,也可以單獨使用!

全文完!

我近期其他文章:

1?Redis高級應(yīng)用

2?聊聊算法——BFS和DFS

3?微服務(wù)通信方式——gRPC

4?分布式任務(wù)調(diào)度系統(tǒng)

5?Dubbo學(xué)習(xí)系列之十八(Skywalking服務(wù)跟蹤)

只寫原創(chuàng),敬請關(guān)注

關(guān)于找一找教程網(wǎng)

本站文章僅代表作者觀點,不代表本站立場,所有文章非營利性免費分享。

本站提供了軟件編程、網(wǎng)站開發(fā)技術(shù)、服務(wù)器運維、人工智能等等IT技術(shù)文章,希望廣大程序員努力學(xué)習(xí),讓我們用科技改變世界。

[聊聊算法——回溯算法]http://www.zyiz.net/tech/detail-135184.html

總結(jié)

以上是生活随笔為你收集整理的回溯java算法_聊聊算法——回溯算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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