java實現回溯算法


最近有在leetcode上面做算法題,已經遇到了兩道回溯算法的題目,感覺一點思路都沒有,現決定將java如何實現回溯算法做一次總結。

 

一、什么叫做回溯算法

(摘抄於百度百科)

回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。許多復雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。

 

(摘抄於他人博客)

在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。(其實回溯法就是對隱式圖的深度優先搜索算法)。 若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。 而若使用回溯法求任一個解時,只要搜索到問題的一個解就可以結束。

 

二、如何使用回溯算法

回溯我認為也就是一種遞歸,有以下四個參數,當然不一定是我所舉例的類型,要看題目而定
一個全局變量集合保存所有滿足條件的答案,舉例:List<List<Integer>> list

一個集合保存一個滿足條件的答案,舉例:List<Integer> tempList

算法問題給所給的輸入條件,這個可能是一個字符串,也可能是一個數組

附加參數(可有可無,視題目而定)

 

下面具體以leetcode上的一道題目為例,這樣能更好的理解

import java.util.ArrayList;
import java.util.List;

public class Permutations {

    //題目描述:Given a collection of distinct integers, return all possible permutations.(給定一組不同的整數,返回其所有的可能組合)
    public List<List<Integer>> permute(int[] nums) {
        //一個全局變量,用於保存所有集合
        List<List<Integer>> list = new ArrayList<>();
        //傳入三個參數,沒有附加參數
        backtrack(list, new ArrayList<>(), nums);
        return list;
    }

    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
        //一個終結條件,也就是滿足條件的時候
        if(tempList.size() == nums.length){
            //全局變量添加一個滿足條件的集合
            list.add(new ArrayList<>(tempList));
        } else{
            for(int i = 0; i < nums.length; i++){
                if(tempList.contains(nums[i])) continue;
                //如果tempList沒有包含nums[i]才添加
                tempList.add(nums[i]);
                //遞歸調用,此時的tempList一直在變化,直到滿足終結條件才結束
                backtrack(list, tempList, nums);
                System.out.println("tempList的內容:"+tempList+"-------"+"i的值:"+i);
                //它移除tempList最后一個元素的作用就是返回上一次調用時的數據,也就是希望返回之前的節點再去重新搜索滿足條件。這樣才能實現回溯
                tempList.remove(tempList.size() - 1);
            }
        }
    }

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

main方法測試,輸出語句的結果顯示如下,可以觀察出回溯的過程

tempList的內容:[1, 2, 3]-------i的值:2
tempList的內容:[1, 2]-------i的值:1
tempList的內容:[1, 3, 2]-------i的值:1
tempList的內容:[1, 3]-------i的值:2
tempList的內容:[1]-------i的值:0
tempList的內容:[2, 1, 3]-------i的值:2
tempList的內容:[2, 1]-------i的值:0
tempList的內容:[2, 3, 1]-------i的值:0
tempList的內容:[2, 3]-------i的值:2
tempList的內容:[2]-------i的值:1
tempList的內容:[3, 1, 2]-------i的值:1
tempList的內容:[3, 1]-------i的值:0
tempList的內容:[3, 2, 1]-------i的值:0
tempList的內容:[3, 2]-------i的值:1
tempList的內容:[3]-------i的值:2

 

我對這道題目的理解是從這個for循環的i=0開始就不斷遞歸,然后在不斷消除集合最末尾元素進行回溯,直到回溯完成。這樣就產生了首位元素是1的各種情況。以此類推,之后再開始for循環i=1,產生首位元素是2的各種情況。

形象點就是一個根結點有1,2,3三個元素,第一次從1出發,尋找最低端滿足條件的結點,然后再返回上一個結點尋找滿足條件的結點,直到返回1,返回1之后再從2開始,以此類推。

 

leetcode上面有關回溯算法的一些題目的實現可查看這個鏈接:https://leetcode.com/problems/permutations/discuss/18239/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partioning)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM