113 路径总和II(2021-06-24)

113. 路径总和II

链接:https://leetcode-cn.com/problems/path-sum-ii/

题目描述见链接内容。

解法1:广度优先搜索

在广度优先搜索时,重新构造了一个queue,原本的queue只用来存放未遍历的节点,现在queue的成员是一个对象,对象中包括了三个属性,node用来存放未遍历的节点,val存放遍历到当前节点前的历史路径求和,history保存当前节点前的历史路径

var pathSum = function (root, targetSum) {
  let result = [];

  if (!root) {
    return [];
  }

  const queue = [{node: root, val: 0, history: []}];

  for (let i = 0; i < queue.length; i++) {
    const {node, val, history} = queue[i];

    if (!node.left && !node.right) {
      if (node.val + val === targetSum) {
        result.push([...history, node.val]);
      }
    }

    if (node.left) {
      queue.push({node: node.left, val: val + node.val, history: [...history, node.val]});
    }

    if (node.right) {
      queue.push({node: node.right, val: val + node.val, history: [...history, node.val]});
    }
  }

  return result;
};
  • 时间复杂度:${O(N)}$N是二叉树节点树
  • 空间复杂度:${O(H)}$H是二叉树深度,最坏情况是${ON)}$,平均复杂度是${O(log N)}$
  • 执行用时:96ms, 在所有JavaScript提交中击败了86%的用户,内存消耗:47.3MB,在所有JavaScript提交中击败了36%的用户

解法2:广度优先搜索2

实际上原理差不多,只是做了如下改动:

  1. 将历史路径求和单独用了一个队列sumQueue表示,与queue同步更新
  2. 没有再保存历史路径,而是用一个Map保存了每一个节点的父节点,发现最终的节点是符合要求的节点时,通过Map不断寻找父节点找出历史路径
var pathSum = function (root, targetSum) {
  if (!root) {
    return [];
  }

  const result = [];
  const queue = [root];
  const sumQueue = [0];

  const map = new Map();

  // 通过向上循环,找出父节点,返回历史路径
  function getParentPath(node) {
    const parentPath = [];

    let current = node;

    while (current) {
      parentPath.unshift(current.val);
      current = map.get(current);
    }

    return parentPath;
  }

  while (queue.length) {
    const node = queue.shift();
    const currentSum = sumQueue.shift();

    if (!node.left && !node.right) {
      if (node.val + currentSum === targetSum) {
        result.push(getParentPath(node));
      }
    } else {
      if (node.left) {
        // 保存父节点
        if (!map.get(node.left)) {
          map.set(node.left, node);
        }
        queue.push(node.left);
        // 更新求和队列
        sumQueue.push(currentSum + node.val);
      }

      if (node.right) {
        // 保存父节点
        if (!map.get(node.right)) {
          map.set(node.right, node);
        }
        queue.push(node.right);
        // 更新求和队列
        sumQueue.push(currentSum + node.val);
      }
    }
  }

  return result;
};
  • 时间复杂度:${O(N)}$N是二叉树节点树
  • 空间复杂度:${O(N)}$N是二叉树节点树
  • 执行用时:112ms, 在所有JavaScript提交中击败了37%的用户,内存消耗:41.7MB,在所有JavaScript提交中击败了49%的用户

深度优先搜索

利用深度优先搜索时,内部的dfs函数加入传递path参数,每次在新的分支递归时,都会产生新的path,在叶子节点处符合要求的话,将对应的path放到结果中

var pathSum = function (root, targetSum) {
  const result = [];

  function dfs(node, sum, path = []) {
    if (!node) {
      return;
    }

    if (!node.left && !node.right) {
      if (node.val === sum) {
        result.push([...path, node.val]);
      }
    }

    if (node.left) {
      dfs(node.left, sum - node.val, [...path, node.val]);
    }

    if (node.right) {
      dfs(node.right, sum - node.val, [...path, node.val]);
    }
  }

  dfs(root, targetSum);

  return result;
};
  • 时间复杂度:${O(N)}$N是二叉树节点树
  • 空间复杂度:${O(N)}$N是二叉树节点树
  • 执行用时:96ms, 在所有JavaScript提交中击败了86%的用户,内存消耗:48.6MB,在所有JavaScript提交中击败了12%的用户
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值