[英]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):
因此,可以遍歷所有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
尺寸的n
, s
落在下列情形只有一個:
s
分為兩個較小的有效模式 s
分為兩個較小的有效模式 對於情況1, s
的格式必須為(_____)
,其中_____
是大小為n - 1
的有效模式。 因此,在這種情況下,對於大小為n - 1
每個有效模式t
,我們只需將t
與(
和)
分別作為前綴和后綴(即s = (t)
)串聯即可構造模式s
。
對於情況2,我們可以將s
划分為uv
,其中u
和v
都是較小的有效模式。 在這種情況下,我們必須考慮u
和v
所有可能模式,其中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.