論文解讀(DAEGC)《Improved Deep Embedded Clustering with Local Structure Preservation》
阿新 • • 發佈:2022-02-19
回溯
0 回溯框架
解決一個回溯問題,實際上就是一個決策樹的遍歷過程。只需要思考 3 個問題:
-
路徑:也就是已經做出的選擇
-
選擇列表:也就是你當前可以做的選擇
-
結束條件:也就是到達決策樹底層,無法再做選擇的條件
回溯演算法的框架:
result = []
def backtrack(路徑, 選擇列表):
if 滿足結束條件:
result.add(路徑)
return
for 選擇 in 選擇列表:
做選擇
backtrack(路徑, 選擇列表)
撤銷選擇
核心: for 迴圈裡面的遞迴,在遞迴呼叫之前「做選擇」,在遞迴呼叫之後「撤銷選擇」
1 問題列表
2 括號生成
2.1 問題重現
數字 n
代表生成括號的對數,請你設計一個函式,用於能夠生成所有可能的並且 有效的 括號組合
示例 1:
輸入:n = 3
輸出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
輸入:n = 1
輸出:["()"]
提示:
1 <= n <= 8
2.2 解題思路
根據回溯演算法的框架,我們需要:
- 一個儲存最終結果的列表
res
,用來儲存所有合法的路徑 - 一個路徑選擇列表
road
,表示當前可以做的選擇
那麼,接下來要討論的就是什麼條件下符合?什麼條件下不符合?(即:回溯繼續條件 && 回溯終止條件)
比如 (())、()()
就是一個合法的括號,))((
就不是一個合法的括號,即:
- 左右括號數量必須相等(繼續條件)
- 不能只出現左(右)括號而不出現右(左)括號(終止條件)
- 當左右括號數量相等且都用完的情況下,得到一個合法的路徑,將結果加入到總結果
res
中(終止條件)
接下來就是回溯的核心:做選擇 && 撤銷選擇
-
做選擇:只有兩種情況,要麼選擇
(
,要麼選擇)
-
做完選擇後,選擇列表
road
發生了該表,繼續進行回溯 -
撤銷選擇:左選擇時選擇了左(右)括號,那麼就撤銷左(右)括號
至此,演算法大題思路已經成型,程式碼如下:
class Solution { //總的結果列表 List<String> res = new ArrayList<>(); public List<String> generateParenthesis(int n) { String road = ""; backtrack(n, n, road, res); return res; } public void backtrack(int left, int right, String road, List<String> res){ //非法條件,回溯終止 if (left < 0 || right < 0) return; if (right < left) return; //合法情況,加入結果 res if (left == 0 && right == 0){ res.add(road); return; } //嘗試新增左括號並撤銷 road += "("; backtrack(left - 1, right, road, res); road = road.substring(0, road.length() - 1); //嘗試新增右括號並撤銷 road += ")"; backtrack(left, right - 1, road, res); road = road.substring(0, road.length() - 1); } }
提交通過!
3 全排列
3.1 問題重現
給定一個不含重複數字的陣列 nums
,返回其 所有可能的全排列 。你可以 按任意順序 返回答案
示例 1:
輸入:nums = [1,2,3]
輸出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
輸入:nums = [0,1]
輸出:[[0,1],[1,0]]
示例 3:
輸入:nums = [1]
輸出:[[1]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums
中的所有整數 **互不相同 **
3.2 解題思路
最後的總結果列表不用多說,必備的 res
還需要一個當前選擇列表 road
,怎麼判斷呢?每次迴圈的時候,判斷一下是否該元素已經被使用,若未被使用,才可以進行回溯
結束條件:當前選擇路徑列表 road
長度等於 nums
的長度時,說明已經兩所有元素使用完,產生了一個合法的路徑,將該路徑加入總結果列表 res
中,本次回溯結束
思路清晰,程式碼如下:
class Solution {
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
LinkedList<Integer> road = new LinkedList<>();
backtrack(nums, road);
return res;
}
public void backtrack(int[] nums, LinkedList<Integer> road){
if (nums.length == road.size()){
res.add(new LinkedList<>(road));
return;
}
for (int num : nums) {
if (road.contains(num)) {
continue;
}
road.add(num);
backtrack(nums, road);
road.removeLast();
}
}
}
提交通過!