簡體   English   中英

如何使用自底向上遞歸為n = 3建立案例?

[英]How to build the case for n=3 using bottom up recursion?

我正在研究來自破解編碼面試的問題,第9.6頁110。

這是問題所在:
實現一種算法以打印所有有效的(例如,n對括號的正確打開和閉合的組合。)
b(1)-“()”
b(2)-“(()),()()”
b(3)-“(((())),(()()),(())(),()(()),()()()”
我正在嘗試使用作者在第107頁上討論的自下而上的遞歸方法-“我們首先知道如何為一個簡單的案例(例如僅包含一個元素的列表)解決問題,並找出如何為以下問題解決問題的方法兩個元素,然后是三個元素,依此類推。這里的關鍵是考慮如何從前一個案例中構建一個案例的解決方案。”

這是我到目前為止的代碼

static void print(int n) {
    print(n, new HashSet<String>(), "", "");
}

static void print(int n, Set<String> combs, String start, String  end) {
    if(n == 0) {
        if(!combs.contains(start + end)) {
            System.out.print(start + end);
            combs.add(start + end);
        }
    } else {
        print(n-1, combs, "(" + start, end +")");
        System.out.print(", ");
        print(n-1, combs, start, end + "()");
        System.out.print(", ");
        print(n-1, combs, "()" + start, end);
    }
}

為了獲得此代碼,我從第一種情況轉到第二種情況。 我看見了
b(2)=“(b(1)),b(1),b(1)”此代碼確實適用於前兩種情況。 我確實在為第三種情況掙扎。 有人可以給我一個提示(不是全部答案,可以轉到書的后面),關於如何從案例2轉到案例3,或者換句話說,使用案例2轉到案例3? 就像你將如何從(()),()()轉到
((())),(()()),(())(),()(()),()()()? 您是否會因為從b(2)到b(3)不起作用而放棄從b(1)到b(2)看到的模式?

我們可以使用以下遞歸公式生成從b(n)到b(n + 1):

  • (b(n-x))b(x)且0 <= x <= n

因此,可以遍歷所有x來擁有所有組合。

碼:

public static ArrayList<String> cal(int num){

    if(num == 0){
        ArrayList<String> list = new ArrayList();
        list.add("");
        return list;
    }else{
        ArrayList<String>result = new ArrayList();
        for(int i = 0; i <= num - 1; i++){
            ArrayList<String> a = cal(i);
            ArrayList<String> b = cal(num - 1 - i);
            for(String x : a){
                for(String y : b){
                    result.add("(" + x + ")" + y);
                }
            }
        }
        return result;
    }
}

輸入:3輸出: ()()(), ()(()), (())(), (()()), ((()))

輸入:4輸出: ()()()(), ()()(()), ()(())(), ()(()()), ()((())), (())()(), (())(()), (()())(), ((()))(), (()()()), (()(())), ((())()), ((()())), (((())))

感謝Khanna111指出我在原始答案中犯的錯誤,該錯誤是不完整的,並且未充分考慮字符串模式。 結果,我相應地更新了我的答案。

請考慮以正確的遞歸公式將Pham Trung的答案歸功於他。 我的回答與他的回答基本相同,只是我從較小的子問題闡述模式構建的方式略有不同(因為我發現更容易解釋我的方法中的細節)。

================================================== ======================

更新解決方案

對於任何有效的模式s尺寸的ns落在下列情形只有一個:

  • 情況1: 不能s分為兩個較小的有效模式
  • 情況2: 可以s分為兩個較小的有效模式

對於情況1, s的格式必須為(_____) ,其中_____是大小為n - 1的有效模式。 因此,在這種情況下,對於大小為n - 1每個有效模式t ,我們只需將t()分別作為前綴和后綴(即s = (t) )串聯即可構造模式s

對於情況2,我們可以將s划分為uv ,其中uv都是較小的有效模式。 在這種情況下,我們必須考慮uv所有可能模式,其中u可以是大小為i = 1, 2, ..., n - 1任何有效模式,而v可以是大小為n - i任何有效模式。 n - i

n = 0 ,顯然只有空字符串是有效的模式,因此我們將dp(0) = { "" }作為我們的基本情況。 下面給出了具有緩存以提高性能的完整實現:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class BalancingBrackets {

    private static Map<Integer, Set<String>> dp = new HashMap<>();

    public static void main(String[] args) {
        Set<String> result = compute(4);

        boolean isFirst = true;
        for (String s : result) {
            if (isFirst) {
                isFirst = false;
                System.out.print(s);
            } else {
                System.out.print(", " + s);
            }
        }
    }

    private static Set<String> compute(Integer n) {
        // Return the cached result if available
        if (dp.containsKey(n)) {
            return dp.get(n);
        }

        Set<String> set = new HashSet<>();

        if (n == 0) {
            // This is the base case with n = 0, which consists only of the
            // empty string
            set.add("");
        } else if (n > 0) {
            // For generating patterns in case 1
            for (String s : compute(n - 1)) {
                set.add("(" + s + ")");
            }

            // For generating patterns in case 2
            for (int i = 1; i < n; i++) {
                Set<String> leftPatterns = compute(i);
                Set<String> rightPatterns = compute(n - i);

                for (String l : leftPatterns) {
                    for (String r : rightPatterns) {
                        set.add(l + r);
                    }
                }
            }
        } else {
            // Input cannot be negative
            throw new IllegalArgumentException("Input cannot be negative.");
        }

        // Cache the solution to save time for computing large size problems
        dp.put(n, set);

        return set;
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM