二叉樹路徑

路徑總和

給你二叉樹的根節(jié)點(diǎn) root 和一個(gè)表示目標(biāo)和的整數(shù) targetSum 。判斷該樹中是否存在 根節(jié)點(diǎn)到葉子節(jié)點(diǎn) 的路徑,這條路徑上所有節(jié)點(diǎn)值相加等于目標(biāo)和 targetSum 。如果存在,返回 true ;否則,返回 false 玩祟。

葉子節(jié)點(diǎn) 是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)。

遞歸

public boolean hasPathSum(TreeNode root, int targetSum) {
    if (root == null) {
        return false;
    }
    if (root.left == null && root.right == null) {
        return targetSum == root.val;
    }
    return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}

沒有寫成以下是因?yàn)樽ぷ唬鏄錇榭招枰祷豧alse

public boolean hasPathSum(TreeNode root, int targetSum) {
    if (root == null) {
        return targetSum == 0;
    }
    return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}

迭代

public boolean hasPathSum(TreeNode root, int targetSum) {
    if (root == null) {
        return false;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    Queue<Integer> sumQueue = new LinkedList<>();
    queue.add(root);
    sumQueue.add(root.val);
    while (!queue.isEmpty()) {
        root = queue.poll();
        int sum = sumQueue.poll();
        if (root.left == null && root.right == null) {
            if (sum == targetSum) {
                return true;
            }
        } else {
            if (root.left != null) {
                queue.add(root.left);
                sumQueue.add(sum + root.left.val);
            }
            if (root.right != null) {
                queue.add(root.right);
                sumQueue.add(sum + root.right.val);
            }
        }
    }
    return false;
}

路徑總和 II

給你二叉樹的根節(jié)點(diǎn) root 和一個(gè)整數(shù)目標(biāo)和 targetSum 卵凑,找出所有 從根節(jié)點(diǎn)到葉子節(jié)點(diǎn) 路徑總和等于給定目標(biāo)和的路徑。

葉子節(jié)點(diǎn) 是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)胜臊。

示例:

給定如下二叉樹勺卢,以及目標(biāo)和 sum = 22

            5
           / \
          4   8
         /   / \
        11  13  4
       /  \    / \
       7   2  5   1

返回:
[
[5,4,11,2],
[5,8,4,5]
]

遞歸

public List<List<Integer>> pathSum(TreeNode root, int sum) {
    List<List<Integer>> ans = new ArrayList<>();
    Stack<Integer> stack = new Stack<>();
    trace(root, sum, 0, ans, stack);
    return ans;
}

public void trace(TreeNode root, int sum, int partSum, List<List<Integer>> lists, Stack<Integer> stack) {
    if (root == null) {
        return;
    }
    partSum += root.val;
    stack.push(root.val);
    if (root.left == null && root.right == null) {
        if (partSum == sum) {
            lists.add(new ArrayList<>(stack));
        }
    }
    trace(root.left, sum, partSum, lists, stack);
    trace(root.right, sum, partSum, lists, stack);
    partSum -= root.val;
    stack.pop();
}

迭代

public List<List<Integer>> pathSum(TreeNode root, int target) {
    List<List<Integer>> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    Queue<List<Integer>> pathQueue = new LinkedList<>();
    queue.add(root);
    pathQueue.add(new ArrayList<>(Arrays.asList(root.val, root.val)));
    while (!queue.isEmpty()) {
        root = queue.poll();
        List<Integer> pathList = pathQueue.poll();
        if (root.left == null && root.right == null) {
            if (pathList.get(0) == target) {
                pathList.remove(0);
                res.add(pathList);
            }
        } else {
            if (root.left != null) {
                queue.add(root.left);
                List<Integer> newPaths = new ArrayList<>(pathList);
                newPaths.set(0, pathList.get(0) + root.left.val);
                newPaths.add(root.left.val);
                pathQueue.add(newPaths);
            }
            if (root.right != null) {
                queue.add(root.right);
                List<Integer> newPaths = new ArrayList<>(pathList);
                newPaths.set(0, pathList.get(0) + root.right.val);
                newPaths.add(root.right.val);
                pathQueue.add(newPaths);
            }
        }
    }
    return res;
}

路徑總和 III

給定一個(gè)二叉樹象对,它的每個(gè)結(jié)點(diǎn)都存放著一個(gè)整數(shù)值黑忱。

找出路徑和等于給定數(shù)值的路徑總數(shù)。

路徑不需要從根節(jié)點(diǎn)開始勒魔,也不需要在葉子節(jié)點(diǎn)結(jié)束甫煞,但是路徑方向必須是向下的(只能從父節(jié)點(diǎn)到子節(jié)點(diǎn))。

二叉樹不超過1000個(gè)節(jié)點(diǎn)冠绢,且節(jié)點(diǎn)數(shù)值范圍是 [-1000000,1000000] 的整數(shù)抚吠。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等于 8 的路徑有:

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

方法一:兩個(gè)DFS
先序遍歷每一個(gè)結(jié)點(diǎn)弟胀,以每一個(gè)結(jié)點(diǎn)作為根尋找滿足和的路徑

private int count;

public int pathSum(TreeNode root, int sum) {
    preOrder(root, sum);
    return count;
}

public void preOrder(TreeNode root, int sum) {
    if (root == null) {
        return;
    }
    trace(root, sum, 0);
    preOrder(root.left, sum);
    preOrder(root.right, sum);
}

private void trace(TreeNode root, int sum, int partSum) {
    if (root == null) {
        return;
    }
    partSum += root.val;
    if (partSum == sum) {
        count++;
    } 
    trace(root.left, sum, partSum);
    trace(root.right, sum, partSum);   
}

方法二:前綴和
如果前綴總和currSum楷力,在節(jié)點(diǎn)A和節(jié)點(diǎn)B處相差target喊式,則位于節(jié)點(diǎn)A和節(jié)點(diǎn)B之間的元素之和是target

private Map<Integer, Integer> map = new HashMap<>();//key:前綴和 value:次數(shù)

public int pathSum(TreeNode root, int sum) {
    map.put(0, 1);
    return trace(root, sum, 0);
}

private int trace(TreeNode root, int sum, int partSum) {
    if (root == null) {
        return 0;
    }
    partSum += root.val;
    int ans = 0;
    ans += map.getOrDefault(partSum - sum, 0);
    map.put(partSum, map.getOrDefault(partSum, 0) + 1);
    ans += trace(root.left, sum, partSum);
    ans += trace(root.right, sum, partSum);
    //回到本層,恢復(fù)狀態(tài)萧朝,不再是前綴了
    map.put(partSum, map.get(partSum) - 1);
    return ans;
}

二叉樹中的最大路徑和

給定一個(gè)非空二叉樹岔留,返回其最大路徑和。

本題中检柬,路徑被定義為一條從樹中任意節(jié)點(diǎn)出發(fā)献联,達(dá)到任意節(jié)點(diǎn)的序列。該路徑至少包含一個(gè)節(jié)點(diǎn)何址,且不一定經(jīng)過根節(jié)點(diǎn)里逆。

示例 1:

輸入: [1,2,3]

       1
      / \
     2   3
輸出: 6

示例 2:

輸入: [-10,9,20,null,null,15,7]

   -10
   / \
  9  20
    /  \
   15   7
輸出: 42

每走到一個(gè)結(jié)點(diǎn),有三個(gè)選擇:

  • 不走了
  • 向左走
  • 向右走
private int max = Integer.MIN_VALUE;

public int maxPathSum(TreeNode root) {
    if (root == null) {
        return 0;
    }
    dfs(root);
    return max;
}

public int dfs (TreeNode root) {
    if (root == null) {
        return 0;
    }
    int left = Math.max(0, dfs(root.left));//為負(fù)數(shù)就不向下走了
    int right = Math.max(0, dfs(root.right));
    max = Math.max(max, left + right + root.val);
    return root.val + Math.max(left, right);//以root為根直路的長(zhǎng)度
}

二叉樹的所有路徑

給你一個(gè)二叉樹的根節(jié)點(diǎn) root 头朱,按 任意順序 运悲,返回所有從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的路徑龄减。
葉子節(jié)點(diǎn) 是指沒有子節(jié)點(diǎn)的節(jié)點(diǎn)项钮。

示例 1:

輸入:root = [1,2,3,null,5]
輸出:["1->2->5","1->3"]

遞歸

private List<String> res = new ArrayList<>();

public List<String> binaryTreePaths(TreeNode root) {
    dfs(root, new Stack<>());
    return res;
}

private void dfs(TreeNode root, Stack<Integer> stack) {
    if (root == null) {
        return;
    }
    stack.add(root.val);
    if (root.left == null && root.right == null) {
        StringBuilder sb = new StringBuilder();
        for (int v : stack) {
            sb.append(v).append("->");
        }
        sb.delete(sb.length() - 2, sb.length());
        res.add(sb.toString());
    }
    dfs(root.left, stack);
    dfs(root.right, stack);
    stack.pop();
}

迭代

public List<String> binaryTreePaths(TreeNode root) {
    List<String> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    Queue<String> pathQueue = new LinkedList<>();
    queue.add(root);
    pathQueue.add(String.valueOf(root.val));
    while (!queue.isEmpty()) {
        root = queue.poll();
        String s = pathQueue.poll();
        if (root.left == null && root.right == null) {
            res.add(s);
        } else {
            if (root.left != null) {
                queue.add(root.left);
                pathQueue.add(s + "->" + root.left.val);
            } 
            if (root.right != null) {
                queue.add(root.right);
                pathQueue.add(s + "->" + root.right.val);
            }
        }
    }
    return res;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市希停,隨后出現(xiàn)的幾起案子烁巫,更是在濱河造成了極大的恐慌,老刑警劉巖宠能,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亚隙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡违崇,警方通過查閱死者的電腦和手機(jī)阿弃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羞延,“玉大人渣淳,你說我怎么就攤上這事“槁幔” “怎么了入愧?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嗤谚。 經(jīng)常有香客問我棺蛛,道長(zhǎng),這世上最難降的妖魔是什么巩步? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任旁赊,我火速辦了婚禮,結(jié)果婚禮上椅野,老公的妹妹穿的比我還像新娘终畅。我一直安慰自己钞钙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布声离。 她就那樣靜靜地躺著芒炼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪术徊。 梳的紋絲不亂的頭發(fā)上本刽,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音赠涮,去河邊找鬼子寓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛笋除,可吹牛的內(nèi)容都是我干的斜友。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼垃它,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼鲜屏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起国拇,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤洛史,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后酱吝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體也殖,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年务热,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了忆嗜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡崎岂,死狀恐怖捆毫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情该镣,我是刑警寧澤冻璃,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站损合,受9級(jí)特大地震影響省艳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嫁审,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一跋炕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧律适,春花似錦辐烂、人聲如沸遏插。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胳嘲。三九已至,卻和暖如春扣草,著一層夾襖步出監(jiān)牢的瞬間了牛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工辰妙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鹰祸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓密浑,卻偏偏與公主長(zhǎng)得像蛙婴,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尔破,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355