递归、DFS感觉好难理解啊

博客讲述刷LeetCode时遇到分割回文串问题,即给定字符串s,将其分割成子串使每个子串为回文串并返回所有分割方案。该问题运用DFS和回溯的递归解法,还给出了完整代码的转载链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

都说递归是一种易于理解的编码方式,但是感觉并没有那么轻松。

今天刷leetCode遇到一个分割回文串的问题,如下:

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

示例:

输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-partitioning
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

其中就有运用DFS和回溯的解法

完整代码如下

 

package com.LeeCode;

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

public class VariesPalindrome {
List<List<String>>list=new ArrayList<List<String>>();
String s;
public List<List<String>> partition(String s) {
//从头到尾递归+回溯。
this.s=s;
//这个是满足的每一个集合
List<String>ll=new ArrayList<String>();
dfs(ll,0);
return list;
}
public void dfs(List<String>ll,int index){
if(index==s.length())
{
list.add(new ArrayList<String>(ll));
return;
}
//i从index开始是因为单个字符也是回文子串
for(int i=index;i<s.length();i++)
{
//如果是回文
if(isPalindrome(index,i)){

//把当前的回文子串s(index,i)加进去
ll.add(s.substring(index,i+1));
dfs(ll,i+1);
//把加进去的回文子串去处。和上面加进去的回文子串是同一个回文子串。
ll.remove(ll.size()-1);
}

}
}
public boolean isPalindrome(int start,int end){
while(start<end){
if(s.charAt(start)!=s.charAt(end))
return false;
start++;
end--;
}
return true;
}

public static void main(String[] args) {
VariesPalindrome variesPalindrome=new VariesPalindrome();
String jj="abnnss";
System.out.println(variesPalindrome.partition(jj));
}
}

转载于:https://www.cnblogs.com/heracles-Mercury/p/11068354.html

<think>嗯,用户问的是如何理解DFS递归。首先,我得先回忆一下DFS的基本概念。深度优先搜索,也就是DFS,是一种用于遍历或搜索树或图的算法。它的特点是尽可能深地访问节点,直到没有更深的节点可访问,然后回溯到之前的节点继续探索。 用户可能已经知道DFS的基本流程,但不太清楚递归的实现方式。所以需要从递归的角度来解释DFS递归本身就是函数自己调用自己,这里的关键是把大问题分解成小问题,每一步处理当前节点,然后递归处理相邻的节点。 接下来,我需要考虑如何将递归DFS结合起来解释。比如,可以举一个树的遍历例子,比如二叉树的前序遍历。递归函数先访问根节点,然后递归处理左子树,再递归处理右子树。这样自然就形成了深度优先的顺序。 用户可能存在的疑问是递归如何实现回溯。这时候需要解释递归的调用栈,每次递归调用都会将当前状态压入栈,当递归返回时,就相当于回溯到上一层,继续执行后续的操作。比如在处理完左子树之后,回到根节点,再处理右子树。 另外,可能需要提到避免重复访问的问题,尤其是在图中。这时候需要维护一个访问标记数组,每次访问节点时标记为已访问,递归时只处理未访问的节点,防止无限循环。 还要注意递归的终止条件,这是递归正确执行的关键。比如在树中,当节点为空时返回,或者在图中所有相邻节点都被访问过时返回。 可能用户在实际应用中遇到了问题,比如递归栈溢出或者逻辑错误,这时候需要强调递归深度和正确维护状态的重要性。例如,图的深度过大时,递归可能导致栈溢出,这时候可能需要改用迭代的DFS实现。 总结一下,解释DFS递归的关键点包括:递归函数的分解(处理当前节点,递归处理子节点)、调用栈与回溯的关系、终止条件的设置、以及状态标记的管理。通过具体的例子,比如树或图的遍历,可以更直观地展示这些概念。</think>要理解DFS(深度优先搜索)的递归实现,可以分以下步骤逐步分析: --- ### 一、DFS的核心思想 **深度优先**:优先沿着一条路径“走到尽头”,再**回溯**到上一个分叉点,探索其他未被访问的分支。 --- ### 二、递归DFS的对应关系 递归的本质是**函数调用自身**,这与DFS的“深入到底再回溯”过程天然契合: 1. **当前节点处理**:访问当前节点 2. **递归子问题**:对当前节点的相邻未访问节点递归调用DFS 3. **隐式回溯**:递归返回时自动回到上一层 --- ### 三、递归DFS的代码框架(以树为例) ```python def dfs(node): if node is None: # 递归终止条件 return print(node.val) # 处理当前节点(如访问、计算等) dfs(node.left) # 递归处理左子树 dfs(node.right) # 递归处理右子树 ``` --- ### 四、关键理解点 #### 1. 递归如何实现“深度优先”? - **优先递归到最深层**:每次递归先处理一个子节点,直到叶子节点(终止条件) - **隐式调用栈**:递归的调用栈自动保存了回溯路径 #### 2. 回溯如何发生? - **递归返回即回溯**:当子递归结束时,自动回到父递归的调用点继续执行 - 例如处理完左子树后,自动回到父节点处理右子树 #### 3. 避免重复访问(图的情况) 需用`visited`标记已访问节点: ```python def dfs(graph, node, visited): if node in visited: return visited.add(node) for neighbor in graph[node]: dfs(graph, neighbor, visited) ``` --- ### 五、实例分析(二叉树前序遍历) 假设树结构: ``` A / \ B C / \ D E ``` 递归执行流程: 1. 访问A → 递归左子树B 2. 访问B → 递归左子树D 3. 访问D → 左右子树为空,返回B 4. B递归右子树E → 访问E → 返回B → 返回A 5. A递归右子树C → 访问C → 结束 输出顺序:**A → B → D → E → C** --- ### 六、常见问题 #### 1. 递归会栈溢出吗? - 树/图深度过大时可能发生,可改用**迭代DFS**(显式栈实现) #### 2. 如何保证正确性? - **终止条件必须明确**(如节点为空或已访问) - **状态标记需谨慎**(如图遍历中标记已访问的时机) --- ### 七、总结 - **递归DFS = 处理当前节点 + 递归所有相邻未访问节点** - **回溯由递归返回机制自动实现** - **适用于树形结构、图的连通性检测、路径查找等问题**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值