跳至主要內容

112, 路径总和

Mike大约 5 分钟binary treeeasybinary treedepth first searchbreadth first search

一、题目描述

给你二叉树的根节点root和一个表示目标和的整数targetSum。判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和targetSum。如果存在,返回true;否则返回false

叶子节点是指没有子节点的节点。

示例 1

输入: root = [5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1], targetSum = 22
输出: true
解释: 等于目标和的根节点到叶节点路径如上图所示。

示例 2

输入: root = [1, 2, 3], targetSum = 5
输出: false
解释: 树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为3
(1 --> 3): 和为4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3
输入: root = [], targetSum = 0
输出: false
解释: 由于树是空的,所以不存在根节点到叶子节点的路径。

提示

  • 树中节点的数目在范围[0, 5000]
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

相关主题

  • 深度优先搜索
  • 广度优先搜索
  • 二叉树

二、题解

#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

方法 1: 深度优先搜索

pub fn has_path_sum(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    //Self::dfs_recur_1(root, target_sum)
    //Self::dfs_iter_1(root, target_sum)
    //Self::dfs_recur_2(root, target_sum)
    Self::dfs_iter_2(root, target_sum)
}

///
/// 1. 找出所有的路径
/// 2. 判断每条路径之和是否等于targetSum
///
fn dfs_recur_1(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    let mut paths = vec![];
    const RECUR: fn(root: Option<Rc<RefCell<TreeNode>>>, Vec<i32>, &mut Vec<Vec<i32>>) =
        |root, mut path, paths| {
            if let Some(curr) = root {
                path.push(curr.borrow().val);
                let left = curr.borrow_mut().left.take();
                let right = curr.borrow_mut().right.take();
                if left.is_none() && right.is_none() {
                    paths.push(path);
                } else {
                    if left.is_some() {
                        RECUR(left, path.clone(), paths);
                    }
                    if right.is_some() {
                        RECUR(right, path, paths);
                    }
                }
            }
        };

    RECUR(root, vec![], &mut paths);

    paths
        .into_iter()
        .any(|p| p.into_iter().sum::<i32>() == target_sum)
}

fn dfs_iter_1(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    let mut paths = vec![];

    if let Some(root) = root {
        let mut stack = vec![(root, vec![])];

        while let Some((curr, mut path)) = stack.pop() {
            path.push(curr.borrow().val);
            let left = curr.borrow_mut().left.take();
            let right = curr.borrow_mut().right.take();

            if left.is_none() && right.is_none() {
                paths.push(path);
            } else {
                if let Some(right) = right {
                    stack.push((right, path.clone()));
                }
                if let Some(left) = left {
                    stack.push((left, path));
                }
            }
        }
    }

    paths
        .into_iter()
        .any(|p| p.into_iter().sum::<i32>() == target_sum)
}

///
/// 累加每条路径,遇到叶子节点时与targetSum进行比较
///
fn dfs_recur_2(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    const RECUR: fn(Option<Rc<RefCell<TreeNode>>>, i32, i32) -> bool =
        |root, sum, target_sum| match root {
            None => false,
            Some(curr) => {
                let curr_sum = curr.borrow().val + sum;
                let left = curr.borrow_mut().left.take();
                let right = curr.borrow_mut().right.take();

                match (left, right) {
                    (None, None) => curr_sum == target_sum,
                    (None, right) => RECUR(right, curr_sum, target_sum),
                    (left, None) => RECUR(left, curr_sum, target_sum),
                    (left, right) => {
                        RECUR(left, curr_sum, target_sum) || RECUR(right, curr_sum, target_sum)
                    }
                }
            }
        };

    RECUR(root, 0, target_sum)
}

fn dfs_iter_2(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    if let Some(root) = root {
        let mut stack = vec![(root, 0)];

        while let Some((curr, sum)) = stack.pop() {
            let curr_sum = curr.borrow().val + sum;
            let left = curr.borrow_mut().left.take();
            let right = curr.borrow_mut().right.take();

            if left.is_none() && right.is_none() && curr_sum == target_sum {
                return true;
            }
            if let Some(right) = right {
                stack.push((right, curr_sum));
            }
            if let Some(left) = left {
                stack.push((left, curr_sum));
            }
        }
    }

    false
}

方法 2: 广度优先搜索

pub fn has_path_sum(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    //Self::bfs_iter_1(root, target_sum
    Self::bfs_iter_2(root, target_sum)
}

///
/// 1. 找出所有的路径
/// 2. 判断每条路径之和是否等于targetSum
///
fn bfs_iter_1(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    let mut paths = vec![];

    if let Some(root) = root {
        let mut queue = VecDeque::from([(root, vec![])]);

        while let Some((curr, mut path)) = queue.pop_front() {
            path.push(curr.borrow().val);
            let left = curr.borrow_mut().left.take();
            let right = curr.borrow_mut().right.take();

            match (left, right) {
                (None, None) => paths.push(path),
                (left, right) => {
                    if let Some(left) = left {
                        queue.push_back((left, path.clone()));
                    }
                    if let Some(right) = right {
                        queue.push_back((right, path));
                    }
                }
            }
        }
    }

    paths
        .into_iter()
        .any(|p| p.into_iter().sum::<i32>() == target_sum)
}

///
/// 累加每条路径,遇到叶子节点时与targetSum进行比较
///
fn bfs_iter_2(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> bool {
    if let Some(root) = root {
        let mut queue = VecDeque::from([(root, 0)]);

        while let Some((curr, sum)) = queue.pop_front() {
            let curr_sum = curr.borrow().val + sum;
            let left = curr.borrow_mut().left.take();
            let right = curr.borrow_mut().right.take();

            match (left, right) {
                (None, None) => {
                    if curr_sum == target_sum {
                        return true;
                    }
                }
                (left, right) => {
                    if let Some(left) = left {
                        queue.push_back((left, curr_sum));
                    }
                    if let Some(right) = right {
                        queue.push_back((right, curr_sum));
                    }
                }
            }
        }
    }

    false
}