回溯

目標(biāo):尋找所有可行解

解決一個(gè)回溯問題,實(shí)際上就是一個(gè)決策樹的遍歷過程

三要素

  1. 路徑:也就是已經(jīng)做出的選擇。
  2. 選擇列表:也就是你當(dāng)前可以做的選擇。
  3. 結(jié)束條件:也就是到達(dá)決策樹底層,無法再做選擇的條件。

算法框架

result = []
def backtrack(路徑, 選擇列表):
    if 滿足結(jié)束條件:
        result.add(路徑)
        return

    for 選擇 in 選擇列表:
        做選擇
        backtrack(路徑, 選擇列表)
        撤銷選擇

1.全排列

public class Permute {

    /**
     * 結(jié)果集
     */
    private static List<List<Integer>> res = new ArrayList<>();

    public static void main(String[] args) {
        int[] nums = {1, 2, 3};
        System.out.println(permute(nums));
    }

    private static List<List<Integer>> permute(int[] nums) {
        //路徑
        LinkedList<Integer> track = new LinkedList<>();
        backtrack(nums, track);
        return res;
    }

    private static void backtrack(int[] nums, LinkedList<Integer> track) {
        // 路徑:記錄在 track 中
        // 選擇列表:nums 中不存在于 track 的那些元素
        // 結(jié)束條件:nums 中的元素全都在 track 中出現(xiàn)
        if (track.size() == nums.length) {
            res.add(new LinkedList<>(track));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (track.contains(nums[i])) {
                continue;
            }
            //做選擇
            track.add(nums[i]);
            //進(jìn)入下一層決策樹
            backtrack(nums, track);
            //撤銷選擇
            track.removeLast();
        }
    }
}

2.重復(fù)數(shù)組的全排列

public class PermuteUnique {
    /**
     * 標(biāo)記已經(jīng)填過的數(shù)
     */
    boolean[] vis;

    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        List<Integer> perm = new ArrayList<Integer>();
        vis = new boolean[nums.length];
        Arrays.sort(nums);
        backtrack(nums, ans, perm);
        return ans;
    }

    /**
     * 回溯搜索
     * @param nums 目標(biāo)數(shù)組
     * @param ans 結(jié)果集
     * @param perm 當(dāng)前路徑
     */
    public void backtrack(int[] nums, List<List<Integer>> ans,  List<Integer> perm) {
        //結(jié)束條件
        if (perm.size() == nums.length) {
            ans.add(new ArrayList<Integer>(perm));
            return;
        }
        for (int i = 0; i < nums.length; ++i) {
            //防止重復(fù)數(shù)字填入,排序后比較
            // 假設(shè)我們有 3 個(gè)重復(fù)數(shù)排完序后相鄰,那么我們一定保證每次都是拿從左往右第一個(gè)未被填過的數(shù)字,
            // 即整個(gè)數(shù)組的狀態(tài)其實(shí)是保證了
            // [未填入,未填入,未填入] 到 [填入,未填入,未填入],
            // 再到 [填入,填入,未填入],最后到 [填入,填入,填入] 的過程的,因此可以達(dá)到去重的目標(biāo)。
            if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) {
                continue;
            }
            //選擇
            perm.add(nums[i]);
            vis[i] = true;
            //下一層回溯
            backtrack(nums, ans,  perm);
            //取消選擇
            vis[i] = false;
            perm.remove(perm.size()-1);
        }
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 深度優(yōu)先搜索/回溯算法(DFS) Ⅰ 解題套路 ? 回溯問題實(shí)際上就是一顆決策樹的遍歷過程,需要思考三...
    LJH_9442閱讀 2,695評(píng)論 0 0
  • 讀完本文,你可以去力扣拿下如下題目: 46.全排列[https://leetcode-cn.com/problem...
    labuladong閱讀 698評(píng)論 0 7
  • 回溯法的實(shí)質(zhì):解決一個(gè)回溯的問題,實(shí)際上就是一個(gè)決策樹的遍歷過程 回溯法算法框架: 1. 路徑:也就是已經(jīng)做出的...
    jessic_chen閱讀 240評(píng)論 0 0
  • 「回溯算法」專題介紹 第 1 節(jié):從全排列問題開始理解回溯搜索算法 引言 大家好,今天要和大家分享的主題是“回溯算...
    李威威閱讀 1,262評(píng)論 0 2
  • 回溯算法實(shí)際上一個(gè)類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當(dāng)發(fā)現(xiàn)已不滿足求解條件時(shí),就“回溯”...
    唯有努力不欺人丶閱讀 1,510評(píng)論 0 4

友情鏈接更多精彩內(nèi)容