【回溯算法 6】括号⽣成(medium)(每日一题)

 🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇

                                      ⭐回溯⭐

🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇


前言

回溯算法是⼀种经典的递归算法,通常⽤于解决组合问题、排列问题和搜索问题等。

回溯算法的基本思想:从⼀个初始状态开始,按照⼀定的规则向前搜索,当搜索到某个状态⽆法前进 时,回退到前⼀个状态,再按照其他的规则搜索。

回溯算法在搜索过程中维护⼀个状态树,通过遍历 状态树来实现对所有可能解的搜索。 回溯算法的核⼼思想:“试错”,即在搜索过程中不断地做出选择,如果选择正确,则继续向前搜 索;否则,回退到上⼀个状态,重新做出选择。

回溯算法通常⽤于解决具有多个解,且每个解都需要 搜索才能找到的问题。


 回溯算法的模板

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

public class Backtracking {
    public void backtracking(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(candidates);
      // 如果需要对candidates进行排序

        backtrack(result, new ArrayList<>(), candidates, target, 0);
    }

    private void backtrack(List<List<Integer>> result, List<Integer> tempList, int[] candidates, int remain, int start) {
        if (remain < 0) { 
       // 如果 remain 小于 0,表示当前的组合不符合要求,直接返回
            return;
        } else if (remain == 0) { 
            // 如果 remain 等于 0,表示当前的组合符合要求,加入到结果中
            result.add(new ArrayList<>(tempList));
        } else {
            for (int i = start; i < candidates.length; i++) {
                if (i > start && candidates[i] == candidates[i - 1]) {
                    continue; 
                  // 避免重复计算,如果当前数字和上一个数字相同,则跳过
                }
                tempList.add(candidates[i]); // 将当前数字加入到临时列表中
                backtrack(result, tempList, candidates, remain - candidates[i], i + 1); 
                // 递归调用,继续向下搜索
                tempList.remove(tempList.size() - 1); 
                // 回溯,将最后加入的数字移除,尝试下一个数字
            }
        }
    }
}

 回溯算法是⼀种⾮常重要的算法,可以解决许多组合问题、排列问题和搜索问题等。回溯算法的核⼼ 思想是搜索状态树,通过遍历状态树来实现对所有可能解的搜索。回溯算法的模板⾮常简单,但是实 现起来需要注意⼀些细节,⽐如如何做出选择、如何撤销选择等。


2. 括号⽣成(medium)

题目链接:22. 括号生成 - 力扣(LeetCode)

问题描述

给定一个正整数 n,生成所有由 n 对括号组成的合法括号序列。合法括号序列需要满足以下条件:

  • 任何时候左括号的数量都不小于右括号的数量。
  • 左括号和右括号的总数相等。

算法思路

采用递归的方式生成所有可能的合法括号序列。递归函数会根据当前位置和已经放置的左括号数量来决定下一步的动作。

递归函数设计

  • 函数名dfs
  • 参数
    • step:当前需要填入的位置。
    • left:当前状态的字符串中的左括号数量。
  • 返回值:无,直接修改全局变量或使用引用传递结果。
  • 函数作用:查找所有合理的括号序列并存储在答案列表中。

递归流程

  1. 递归结束条件
    • 当前状态字符串长度与 2 * n 相等时,记录当前状态并返回。
  2. 递归过程
    • 放置左括号:如果当前左括号数量小于 n,则可以在当前状态的字符串末尾添加左括号并继续递归。递归结束后撤销添加操作。
    • 放置右括号:如果当前右括号数量小于左括号数量,可以在当前状态的字符串末尾添加右括号并递归。递归结束后撤销添加操作。

 代码实现:

class Solution {
    // 写着这道题最主要的点是要找到有效括号的条件:
    // 1.左括号和右括号数量相等
    // 2.在任何一个有效括号的子串中左括号的数量大于等于右括号 ***
    // 剩下的就是dfs遍历剪枝
    int left=0,right=0;
    StringBuffer path;
    List<String> ret;

    public List<String> generateParenthesis(int n) {
      path = new StringBuffer();
      ret = new ArrayList<>();
      dfs(n);
      return ret;
    }

    private void dfs(int n) {
        if(right == n){
            ret.add(path.toString());
            return;
        }
        //添加左括号 
        if(left<n){
            path.append('(');
            left++;
            dfs(n);
            //回溯
            path.deleteCharAt(path.length()-1);
            left--;
        }
        //添加右括号
        right++;
        //剪枝
        if(left<right){
            right--;
            return;
        }
        path.append(')');
        dfs(n);
        path.deleteCharAt(path.length()-1);
        right--;
    }
}


总结

动动手点个赞会让作者更开心,感谢阅览,加油各位 !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值