关于回溯算法

关于回溯算法

问题描述:

关于力扣22题

使用递归的回溯算法实现,波波老师这里我发现一个问题,就是直接在递归函数外面进行变量(本题中的leftCount, rightCount)的改变,无论是++还是+=1跟我想象的答案都不一样,但是如果直接在递归函数中+1就是正确答案,这是什么原因啊老师。虽然感觉这问题很蠢但我还是想不通,明明递归带进去的值都是一样的,结果竟然完全不同

相关代码:

​import java.util.LinkedList;
import java.util.List;

class Solution {
/**
* LC.22 括号生成:生成n对括号所有的有效组合
*/
public List<String> generateParenthesis(int n) {
//接受答案string的链表
List<String> res = new LinkedList<>();
//然后调用回溯递归方法
String str = "";
generateParenthesis(n, 0, 0, str, res);
return res;
}

/**
* 递归回溯方法
* 我觉得无从下手的原因有两条
* 1.没有看出左括号数与右括号数的三种情况递归中不同处理
* 而是想的是算出所有可能性,再去判断括号合法性
* 2. 要注意递归函数中是String,需要添加东西时再改成StringBuilder
*
* @param n :括号的对数,当leftCount==rightCount==n的时候 说明可以添加进链表
* @param leftCount :记录左括号的个数
* @param rightCount : 记录右括号的个数
* @param str :传入的字符串,递归的时候一定要固定住当前的字符
* @param res : 答案添加至链表
* 不需要返回值 已经添加再链表里了
*/
private void generateParenthesis(int n, int leftCount, int rightCount, String str, List<String> res) {
//1.一旦leftCount<rightCount 括号无效直接返回
if (rightCount > leftCount) {
return;
}

//2. 一旦left==right==n 直接添加
if (rightCount == n && leftCount == n) {
/**有可能添加元素一样 增加一个判断*/
// System.out.println(str + " Added!");
res.add(str);
return;
}

//3.如果left>=right 只要left<n 就递归添加左括号 只要right<n 递归添加右括号
StringBuilder stringBuilder = new StringBuilder(str);

if (leftCount < n) {
// System.out.println("cur str="+str+" Add (");
// System.out.println("leftCount=" + leftCount + " rightCount=" + rightCount);

stringBuilder.append("(");
// leftCount+=1;
generateParenthesis(n, leftCount + 1, rightCount, stringBuilder.toString(), res);
}

if (rightCount <= leftCount) {
// System.out.println("cur str="+str+" Add )");
// System.out.println("leftCount=" + leftCount + " rightCount=" + rightCount);
stringBuilder.append(")");
// rightCount++;
generateParenthesis(n, leftCount, rightCount + 1, stringBuilder.toString(), res);
}
}

}


正在回答

登陆购买课程后可参与讨论,去登陆

1回答

你的整个思路是正确的,但问题在于,如果 leftCount < n 同时 rightCount <= leftCount 的话,在你的 递归过程中,stringBuilder 先添加了一个左括号,然后在同层,有添加了一个右括号,可实际上,你要表达的逻辑,在每次递归调用中,只能添加一个括号(或左或右)。


所以,你需要在添加左括号以后,将添加的左括号删掉。加上一句话就正确了:


private void generateParenthesis(int n, int leftCount, int rightCount, String str, List<String> res) {
        
    if (rightCount > leftCount) return;

    if (rightCount == n && leftCount == n) {
        res.add(str);
        return;
    }

    StringBuilder stringBuilder = new StringBuilder(str);
    if (leftCount < n) {
        stringBuilder.append("(");
        generateParenthesis(n, leftCount + 1, rightCount, stringBuilder.toString(), res);
        
        // 在这里将添加的左括号删掉!!!!    
        stringBuilder.deleteCharAt(stringBuilder.length() - 1);
    }
        
    if (rightCount <= leftCount) {
       stringBuilder.append(")");
       generateParenthesis(n, leftCount, rightCount + 1, stringBuilder.toString(), res);
    }
}


另外,整个逻辑其实可以不使用 StringBuilder,下面的代码,我基于你的代码,完全使用 String。而且,这样做,我不需要做这个“删掉”的动作。请仔细体会这是为什么。


    private void generateParenthesis(int n, int leftCount, int rightCount, String str, List<String> res) {
        
        if (rightCount > leftCount) return;
        
        if (rightCount == n && leftCount == n) {
            res.add(str);
            return;
        }
        
        if (leftCount < n)
            generateParenthesis(n, leftCount + 1, rightCount, str + "(", res);
        
        if (rightCount <= leftCount)
            generateParenthesis(n, leftCount, rightCount + 1, str + ")", res);
   
    }


继续加油!:)

  • 宇宇子 提问者 #1

    我觉得应该是 如果现在已经添加了"(",下面有两种递归路径一条是添加左括号一条是添加右括号

    如果使用原来的代码的话添加完左括号res="( (" ,此时再进行第二条路径的递归就不是"("+")",而是"( ("+“)”自然就会少考虑情况。关于这点我觉得可以三种解决方法:

    1. 像老师一样采用删除这个操作 添加左括号后再将SringBuilder变量删除

    2. 两个方法中分别对当前的String转化器StringBuilder,比如一个设置为stringBuilder1,一个stringBuilder2

    3. 直接使用Str,如果直接使用字符串进行增加,此时对于添加左右括号的递归路径而言,当前情况的字符串是固定的,所以自然不需要删除操作


    2021-09-09 10:28:29
  • liuyubobobo 回复 提问者 宇宇子 #2

    赞!!:)

    2021-09-09 13:56:03
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
算法与数据结构
  • 参与学习       2583    人
  • 解答问题       1082    个

慕课网算法名师Liuyubobobo,5年集大成之作 从0到工作5年,算法与数据结构系统解决方案

了解课程
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师