算法_01:子集求和問題及變種問題匯總

問題綜述

子集遍歷求和是算法中比較基礎(chǔ)的一種以至于在筆試和刷題中頻繁出現(xiàn)。在此總結(jié)了一下已有的幾種遍歷方法以及遇到的變種問題的解決方法。

解法一:回溯法子集遍歷

本題的回溯法實(shí)則應(yīng)用了深度優(yōu)先遍歷(DFS)的思想,先將子集從空集補(bǔ)充到最大集再通過遞歸和循環(huán)邊界條件的設(shè)置實(shí)現(xiàn)回溯。
以下代碼顯示了子集是如何一一生成的:

import java.util.ArrayList;

public class SumofSubset {
        
        public ArrayList<Integer> list = new ArrayList<Integer>();   //用于存放求取子集中的元素
        //求取數(shù)組鏈表中元素和
        public int getSum(ArrayList<Integer> list) {
            int sum = 0;
            for(int i = 0;i < list.size();i++)
                sum += list.get(i);
            return sum;
        }
        
        public void getSubSet(int[] A, int m, int step) {
            while(step < A.length) {
                    System.out.println("進(jìn)入"+step);
                list.add(A[step]);   //遞歸執(zhí)行語句,向數(shù)組鏈表中添加一個元素
                System.out.println(list);
                step++;
                getSubSet(A, m, step);
                System.out.println("delete"+list.remove(list.size() - 1));
                System.out.println(list);
                System.out.println("結(jié)束step"+(step-1));//回溯執(zhí)行語句,刪除數(shù)組鏈表最后一個元素
            }
        }
        
        public static void main(String[] args) {
            SumofSubset test = new SumofSubset();
            int[] A = new int[6];
            for(int i = 0;i < 6;i++) {
                A[i] = i + 1;
            }
            test.getSubSet(A, 8, 0);
    } 
}

可見元素個數(shù)為6的集合{1,2,3,4,5,6}回溯遍歷順序如下:

進(jìn)入0
[1]
進(jìn)入1
[1, 2]
進(jìn)入2
[1, 2, 3]
進(jìn)入3
[1, 2, 3, 4]
進(jìn)入4
[1, 2, 3, 4, 5]
進(jìn)入5
[1, 2, 3, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 2, 3, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[1, 2, 3, 5]
進(jìn)入5
[1, 2, 3, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 2, 3, 6]
delete6
結(jié)束step5
delete3
結(jié)束step2
進(jìn)入3
[1, 2, 4]
進(jìn)入4
[1, 2, 4, 5]
進(jìn)入5
[1, 2, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 2, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[1, 2, 5]
進(jìn)入5
[1, 2, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 2, 6]
delete6
結(jié)束step5
delete2
結(jié)束step1
進(jìn)入2
[1, 3]
進(jìn)入3
[1, 3, 4]
進(jìn)入4
[1, 3, 4, 5]
進(jìn)入5
[1, 3, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 3, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[1, 3, 5]
進(jìn)入5
[1, 3, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 3, 6]
delete6
結(jié)束step5
delete3
結(jié)束step2
進(jìn)入3
[1, 4]
進(jìn)入4
[1, 4, 5]
進(jìn)入5
[1, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[1, 5]
進(jìn)入5
[1, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[1, 6]
delete6
結(jié)束step5
delete1
結(jié)束step0
進(jìn)入1
[2]
進(jìn)入2
[2, 3]
進(jìn)入3
[2, 3, 4]
進(jìn)入4
[2, 3, 4, 5]
進(jìn)入5
[2, 3, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[2, 3, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[2, 3, 5]
進(jìn)入5
[2, 3, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[2, 3, 6]
delete6
結(jié)束step5
delete3
結(jié)束step2
進(jìn)入3
[2, 4]
進(jìn)入4
[2, 4, 5]
進(jìn)入5
[2, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[2, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[2, 5]
進(jìn)入5
[2, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[2, 6]
delete6
結(jié)束step5
delete2
結(jié)束step1
進(jìn)入2
[3]
進(jìn)入3
[3, 4]
進(jìn)入4
[3, 4, 5]
進(jìn)入5
[3, 4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[3, 4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[3, 5]
進(jìn)入5
[3, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[3, 6]
delete6
結(jié)束step5
delete3
結(jié)束step2
進(jìn)入3
[4]
進(jìn)入4
[4, 5]
進(jìn)入5
[4, 5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[4, 6]
delete6
結(jié)束step5
delete4
結(jié)束step3
進(jìn)入4
[5]
進(jìn)入5
[5, 6]
delete6
結(jié)束step5
delete5
結(jié)束step4
進(jìn)入5
[6]
delete6
結(jié)束step5

想必聰明的人看到前幾行就大概厘清了回溯法遍歷的順序?;厮莘ㄏ啾扔谏疃葍?yōu)先遍歷的優(yōu)勢在于當(dāng)判斷不滿足條件后,算法能夠及時浪子回頭。然而這也僅僅是相對而言的優(yōu)勢,是否“回頭”判斷語句的引入毫無疑問增加了算法的時間復(fù)雜度,因此當(dāng)解集位于較淺的幾個枝椏時,引入“回頭”判定能夠有效減少無意義的遍歷,反之當(dāng)解集位于近葉枝椏處時,引入“回頭判定”將會增加算法的耗時。
而引入狀態(tài)樹的概念則更便于理解DFS在回溯中的應(yīng)用。從元素在與不在子集這兩種狀態(tài)來考慮,因為每個元素都有兩種狀態(tài),從而構(gòu)建了一個廣義上的二叉樹。

import java.util.ArrayList;

public class SubSet {
    
    public int getSum1(boolean[] visited, int[] A) {
        int sum = 0;
        for(int i = 0;i < A.length;i++) {
            if(visited[i])
                sum += A[i];
        }
        return sum;
    }
    
    public void getSubSet1(boolean[] visited, int[] A, int m, int step) {
        if(step == A.length) {
            if(getSum1(visited, A) == m) {
                for(int i = 0;i < A.length;i++) {
                    if(visited[i])
                        System.out.print(A[i]+" ");
                }
                System.out.println();
            }
            return;
        }
        visited[step] = true;
        getSubSet1(visited, A, m, step + 1);
        visited[step] = false;
        getSubSet1(visited, A, m, step + 1);
    }
    
    public static void main(String[] args) {
        SubSet test = new SubSet();
        int[] A = new int[6];
        boolean[] visited = new boolean[6];
        for(int i = 0;i < 6;i++) {
            A[i] = i + 1;
            visited[i] = false;
        }
        test.getSubSet1(visited, A, 8, 0);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 1)這本書為什么值得看: Python語言描述,如果學(xué)的Python用這本書學(xué)數(shù)據(jù)結(jié)構(gòu)更合適 2016年出版,內(nèi)容...
    孫懷闊閱讀 12,944評論 0 15
  • 老師說:身教言傳。讓我想起學(xué)生期做班級干部的時候:以身做則。上課積極發(fā)言,認(rèn)真做作業(yè)復(fù)習(xí),做好值日生幫同學(xué)打掃,及...
    Una笑笑閱讀 313評論 0 0
  • 實(shí)現(xiàn)獲取下一個排列的函數(shù),算法需要將給定數(shù)字序列重新排列成字典序中下一個更大的排列。 如果不存在下一個更大的排列,...
    小白學(xué)編程閱讀 234評論 0 0
  • 是誰的琴弦,撥動了心湖的漣漪, 與你相遇,是最溫暖的的悸動, 依偎幽靜的夜色, 細(xì)酌一杯香茗, 沐浴思念的幸福, ...
    染指曇花笑閱讀 259評論 0 0

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