如果说二叉树的遍历属于基础部分,那二叉树中的回溯与双指针就属于进阶内容了,但不不用担心这两个技巧并不难。
接下来我们来看一道经典的力扣题:
112.路径总和(经典回溯)
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
本题我们需要找一条符合条件的路径,而这个二叉树并不是搜索二叉树,只能采用穷举的方法,而穷举也是有技巧的,并不是一次一次从跟节点穷举,而是通过子节点返回的值判断穷举是否成功,否则就回溯。回溯虽然挺起来挺高大上的,其实在二叉树中大部分都是通过递归解决问题,而如果递归函数中有意义明确的返回值,基本上就会有回溯的过程,所以回溯的关键即就在于返回值的确定以及对返回值的处理
那么接下来就简单了许多,只需要按照递归三件套进行即可。
-
确定递归函数的参数与返回类型
参数:需要二叉树的根节点,还需要一个计数器,这个计数器用来计算二叉树的一条边之和是否正好是目标和。
返回值:如果计数器归0说明穷举成功返回true,而既然子节点若返回true,那么父节点也即返回ture返回到顶层即可,若为false则返回false。 -
确定终止条件
不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。如果最后count == 0,同时到了叶子节点的话,说明找到了目标和返回true。
如果遍历到了叶子节点,count不为0,就是没找到返回false。
-
确定单层逻辑
因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。
完整代码:
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {number} targetSum
* @return {boolean}
*/
var hasPathSum = function(root, targetSum) {
function dfs(node,count){
if(count===0&&!node.left&&!node.right) return true//找到了节点
if(!node.left&&!node.right) return false //未找到节点
if(node.left){
count-=node.left.val
if(dfs(node.left,count)) return true
count+=node.left.val//未命中,则回溯
}
if(node.right){
count-=node.right.val
if(dfs(node.right,count)) return true
count+=node.right.val//未命中,则回溯
}
return false
}
if(!root) return false
return dfs(root,targetSum-root.val)
}
501.二叉树中的众数(双指针)
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
- 给定一个pre初始值为root,在放入root.left后pre更新为root.left
- 没次递归拿pre与cur进行比较即可
完整代码:
var findMode = function(root) {
// 不使用额外空间,使用中序遍历,设置出现最大次数初始值为1
let count = 0,maxCount = 1;
let pre = root,res = [];
// 1.确定递归函数及函数参数
const travelTree = function(cur) {
// 2. 确定递归终止条件
if(cur === null) {
return ;
}
travelTree(cur.left);
// 3. 单层递归逻辑
if(pre.val === cur.val) {
count++;
}else {
count = 1;
}
pre = cur;
if(count === maxCount) {
res.push(cur.val);
}
if(count > maxCount) {
res = [];
maxCount = count;
res.push(cur.val);
}
travelTree(cur.right);
}
travelTree(root);
return res;
};