zl程序教程

您现在的位置是:首页 >  其他

当前栏目

路径总和题型整理

2023-03-14 22:51:08 时间

题型1:easy

深度优先搜索

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum)
    {
        if (root == NULL) 
            return false;
        if (targetSum == root->val && root->left == NULL && root->right == NULL) return true;
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
    }
};

广度优先搜索

  • 记录根节点到每个节点的路径总和,防止重复计算
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum)
    {
        if (root == NULL) 
            return false;
        queue<pair<TreeNode*, int>> q;
        q.push({ root,root->val });
        while (!q.empty())
        {
            int sum = q.front().second;
            TreeNode* temp = q.front().first;
            q.pop();
            if (!temp->left && !temp->right)
            {
                if(sum==targetSum)
                return true;
                continue;
            }
            //同时朝着当前根节点的左右子树探索
            //探索的同时记录根节点到每个节点的路径和
            if (temp->left)
                q.push({ temp->left,temp->left->val + sum });
            if (temp->right)
                q.push({ temp->right,temp->right->val+sum });
        }
        return false;
    }
};

类回溯法

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum)
    {
        if (root == NULL) 
            return false;
        return backTravel(root,targetSum,root->val);
    }
    bool backTravel(TreeNode* root,int targetSum,int sum)
    {
        bool Lfind=false, Lright=false;
        if (!root) return false;
        if (!root->left && !root->right &&sum == targetSum)
            return true;
        if (root->left)
              Lfind=backTravel(root->left, targetSum, sum+root->left->val);
        if (root->right)
              Lright = backTravel(root->right, targetSum, sum+root->right->val);
        return Lfind || Lright;
    }
};

题型2:medium

回溯模板解题

class Solution {
  public:
      vector<vector<int>> pathSum(TreeNode* root, int targetSum) 
      {
          vector<vector<int>> ret;
          if (root == NULL)
              return ret;
          vector<int> cur;
          backTrave(ret,cur,root, targetSum);
          return ret;
      }
      void backTrave(vector<vector<int>>& ret, vector<int>& cur, TreeNode* root, int targetSum)
      {
          if (root == NULL) return;
          if (root->left == NULL && root->right == NULL)
          {
              cur.push_back(root->val);
              if (accumulate(cur.begin(), cur.end(), 0) == targetSum)
                  ret.push_back(cur);
              //如果当前是找到了一个解,那么回溯,寻找其他可能解
              //如果当前节点是叶子节点,那么再往下找,也不会得到正确解,也需要回溯
              cur.pop_back();
              return;
          }
          else
          {
              cur.push_back(root->val);
              //先从左子树开始找,如果无法找到合适解,去右子树里面找
              //如果左子树里面找到了合适解,要去右子树里面找还有无其他合适解
              backTrave(ret, cur, root->left, targetSum);
              backTrave(ret, cur, root->right, targetSum);
              //如果当前左右子树都无法找到合适解,说明当前根的两个分支走不通,需要返回上一层,寻找别的路径走
              //那么进行回溯,来到上一层,走另一个分支,即如果当前根是上一层的左子树,那么回到上一层后需要到右子树里面寻找可能解
              cur.pop_back();
          }
      }
  };

回溯模板第二种简化写法

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;

    void dfs(TreeNode* root, int sum) {
        if (root == nullptr) {
            return;
        }
        path.emplace_back(root->val);
        sum -= root->val;
        if (root->left == nullptr && root->right == nullptr && sum == 0) {
            ret.emplace_back(path);
        }
        dfs(root->left, sum);
        dfs(root->right, sum);
        path.pop_back();
    }

    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        dfs(root, sum);
        return ret;
    }
};

广度优先遍历—BFS

  • 先来看看BFS的两个模板
  • 模板一:如果不需要确定当前遍历到了哪一层,BFS模板如下
while queue 不空:
    cur = queue.pop()
    if cur 有效且未被访问过:
        进行处理
    for 节点 in cur 的所有相邻节点:
        if 该节点有效:
            queue.push(该节点)
  • 模板二:如果要确定当前遍历到了哪一层,BFS模板如下。 这里增加了level表示当前遍历到二叉树中的哪一层了,也可以理解为在一个图中,现在已经走了多少步了。size表示在当前遍历层有多少个元素,也就是队列中的元素数,我们把这些元素一次性遍历完,即把当前层的所有元素都向外走了一步。
level = 0
while queue 不空:
    size = queue.size()
    while (size --) {
        cur = queue.pop()
        if cur 有效且未被访问过:
            进行处理
        for 节点 in cur的所有相邻节点:
            if 该节点有效:
                queue.push(该节点)
    }
    level ++;

上面两个是通用模板,在任何题目中都可以用,是要记住的!

  • 本题的解法:本题要求所有的路径,不需要按层遍历,因此使用模板一。
  • 我们也可以采用广度优先搜索的方式,遍历这棵树。当我们遍历到叶子节点,且此时路径和恰为目标和时,我们就找到了一条满足条件的路径。
  • 为了节省空间,我们使用哈希表记录树中的每一个节点的父节点。每次找到一个满足条件的节点,我们就从该节点出发不断向父节点迭代,即可还原出从根节点到当前节点的路径。
class Solution {
public:
    vector<vector<int>> ret;
    unordered_map<TreeNode*, TreeNode*> parent;

    void getPath(TreeNode* node) {
        vector<int> tmp;
        while (node != nullptr) {
            tmp.emplace_back(node->val);
            node = parent[node];
        }
        reverse(tmp.begin(), tmp.end());
        ret.emplace_back(tmp);
    }

    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        if (root == nullptr) {
            return ret;
        }

        queue<TreeNode*> que_node;
        queue<int> que_sum;
        que_node.emplace(root);
        que_sum.emplace(0);

        while (!que_node.empty()) {
            TreeNode* node = que_node.front();
            que_node.pop();
            int rec = que_sum.front() + node->val;
            que_sum.pop();

            if (node->left == nullptr && node->right == nullptr) {
                if (rec == sum) {
                    getPath(node);
                }
            } else {
                if (node->left != nullptr) {
                    parent[node->left] = node;
                    que_node.emplace(node->left);
                    que_sum.emplace(rec);
                }
                if (node->right != nullptr) {
                    parent[node->right] = node;
                    que_node.emplace(node->right);
                    que_sum.emplace(rec);
                }
            }
        }

        return ret;
    }
};