二叉树中的最大路径和 + 把数组排成最小的数

57 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情

1 二叉树中的最大路径和

一、题目描述

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

示例 1:

输入:root = [1,2,3]

输出:6

解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

输入:root = [-10,9,20,null,null,15,7]

输出:42

解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:

树中节点数目范围是 [1, 3 * 104]

-1000 <= Node.val <= 1000

二、思路讲解

自底向上扫描节点,计算节点的最大值和向上的最大贡献值

一个节点的最大值为:节点值 + 左子树贡献值+ 右子树贡献值

一个节点向上贡献的最大值为: 节点值 + max{左子树贡献值, 右子树贡献值}

如果某个子树的贡献值为负,则不加上这个贡献值。

然后统计全局最大的那个值即可。

三、java代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
 
    int big = Integer.MIN_VALUE;
 
    public int maxPathSum(TreeNode root) {
        dfs(root);
        return big;
    }
 
    int dfs(TreeNode node){
        if(node==null){
            return 0;
        }
        int left = Math.max(dfs(node.left), 0);
        int right = Math.max(dfs(node.right), 0);
        
        //该节点最大值
        int res = node.val + left + right;
        big = Math.max(big, res);
 
        //返回该节点向上贡献的最大值
        return node.val + Math.max(left, right);
    }
}

四、时空复杂度

时间复杂度: O(N)

空间复杂度: O(1)

2 把数组排成最小的数

一、题目描述

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

示例 1:

输入: [10,2]

输出: "102"

示例 2:

输入: [3,30,34,5,9]

输出: "3033459"

提示:

0 < nums.length <= 100

说明:

输出结果可能非常大,所以你需要返回一个字符串而不是整数

拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0

二、思路讲解

我们可以看到,最高位最小的数字应该放在前面;最高位相同的,次高位小的数字在前面。所以我们将数字转为字符串,方便比较每一位。

如何定义大小呢?例如3和30相比,显然将30放在3前面,组成的数字要更小,因为330>303。那么就很显而易见了,比较a、b两个数字“大小”的方式就是 a+b<b+a,则说明a应该放在b前面。

于是我们基于快速排序,自定义排序规则。

三、Java代码实现

class Solution {
 
    public String minNumber(int[] nums) {
 
        int len = nums.length;
        String []a = new String[len];
 
        for(int i=0; i<len; i++) {
            a[i] = String.valueOf(nums[i]);
        }
 
        quickSort(a, 0, len-1);
 
        StringBuilder res = new StringBuilder("");
        for(int i=0; i<len; i++) {
            res.append(a[i]);
        }
        return res.toString();
    }
 
    /**
    * 快速排序
    */
    void quickSort(String []a, int i, int j) {
        if(i >= j) {
            return;
        }
        int k = partition(a, i, j);
        quickSort(a, i, k-1);
        quickSort(a, k+1, j);
    }
 
    /**
    * 自定义规则的partition排序
    */
    int partition(String []a, int i, int j) {
        String position = a[i];
        while(i < j) {
            while(i<j && ((a[j]+position).compareTo((position+a[j]))>=0)) {
                j--;
            }
            a[i] = a[j];
            while(i<j && ((a[i]+position).compareTo((position+a[i]))<=0)) {
                i++;
            }
            a[j] = a[i];
        }
        a[i] = position;
        return i;
    }
}

四、时空复杂度分析

时间复杂度: O(NlogN) 快速排序的时间复杂度

空间复杂度: O(N) StringBuilder的长度