尾递归
定义:某个方法在其最后调用自身进行递归,并且这个递归调用一定是该方法做的最后一件事。当需要返回值时是return f(n),没有返回就直接是f(n)。
误区:这个f(n)外不能加其他东西,因为这就不是最后一件事了。比如如果有返回值的,你不能:乘个常数 return 3*f(n);乘个n return n*f(n);甚至是 f(n)+f(n-1),这些都不算是尾递归。
尾递归转循环比较简单,增加一个变量或对象数组,记录在递归中发生变化的量即可。
包括类似斐波那契数列的循环写法,使用两个变量记录f(n)和f(n-1)即可。
一般递归
LeetCode 112题。
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
For example:
Given the below binary tree and sum = 22,
![]()
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
在Tree数据结构中,递归的方法用的很多。通常也是将当前节点的问题分解为其左子树和右子树两个子问题,再进行合并进行求解。
Java递归代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null)
return false;
if(root.left == null && root.right == null && sum == root.val)
return true;
return hasPathSum(root.left, sum-root.val) || hasPathSum(root.right, sum-root.val);
}
}
递归的好处在于代码简洁,可读性强,容易维护。然而缺点往往更致命,在于其占用堆栈(尤其是堆)厉害。易导致内存溢出。因此,有时候需要将递归方法转变成非递归的方法。
将一般非尾递归的方法转换成循环的方法,通常需要一个新的数据结构来代替Java内存结构中的栈。自然就是使用一样原理的stack数据结构。
递归->循环:
递归中发生变化的变量(递归返回值)->循环中每一次处理完相应变量存入stack中(push进栈)
递归中使用递归返回值->循环中取出stack中的值进行处理(pop出栈)
本题的非递归方法,起点和结束点不变。起点从根节点root开始(将root push进栈),结束于遍历完整棵Tree为止(所有对象pop出栈,栈为空,最后pop出栈的为root)。
Java非递归代码如下:
public boolean hasPathSum(TreeNode root, int sum) {
Stack <TreeNode> stack = new Stack<> ();
stack.push(root) ;
while (!stack.isEmpty() && root != null){
TreeNode cur = stack.pop() ;
if (cur.left == null && cur.right == null){
if (cur.val == sum ) return true ;
}
if (cur.right != null) {
cur.right.val = cur.val + cur.right.val ;
stack.push(cur.right) ;
}
if (cur.left != null) {
cur.left.val = cur.val + cur.left.val;
stack.push(cur.left);
}
}
return false ;
}
LeetCode 101. Symmetric Tree
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
For example, this binary tree [1,2,2,3,4,4,3] is symmetric:
1
/ \
2 2
/ \ / \
3 4 4 3
But the following [1,2,2,null,3,null,3] is not:
1
/ \
2 2
\ \
3 3
Note:
Bonus points if you could solve it both recursively and iteratively.
Java递归代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public boolean isSymmetric(TreeNode root) {
return root==null || isSymmetricHelp(root.left, root.right);
}
private boolean isSymmetricHelp(TreeNode left, TreeNode right){
if(left==null || right==null)
return left==right;
if(left.val!=right.val)
return false;
return isSymmetricHelp(left.left, right.right) && isSymmetricHelp(left.right, right.left);//判断左子树的左子树与右子树的右子树,和 左子树的右子树与右子树的左子树 即可
}
递归->循环:
递归中发生变化的变量(递归返回值)->循环中每一次处理完相应变量存入stack中(push进栈)
递归中使用递归返回值->循环中取出stack中的值进行处理(pop出栈)
Java非递归代码如下:
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode left, right;
if(root.left!=null){
if(root.right==null) return false;
stack.push(root.left);
stack.push(root.right);
}
else if(root.right!=null){
return false;
}
while(!stack.empty()){
if(stack.size()%2!=0) return false;
right = stack.pop();
left = stack.pop();
if(right.val!=left.val) return false;
if(left.left!=null){
if(right.right==null) return false;
stack.push(left.left);
stack.push(right.right);
}
else if(right.right!=null){
return false;
}
if(left.right!=null){
if(right.left==null) return false;
stack.push(left.right);
stack.push(right.left);
}
else if(right.left!=null){
return false;
}
}
return true;
}