1. 最短的单词编码
单词数组 words 的 有效编码 由任意助记字符串 s 和下标数组 indices 组成,且满足:
- words.length == indices.length
- 助记字符串 s 以 ‘#’ 字符结尾
- 对于每个下标 indices[i] ,s 的一个从 indices[i] 开始、到下一个 ‘#’ 字符结束(但不包括 ‘#’)的 子字符串 恰好与 words[i] 相等
给定一个单词数组 words ,返回成功对 words 进行编码的最小助记字符串 s 的长度 。
输入:words = [“time”, “me”, “bell”]
输出:10
解释:一组有效编码为 s = “time#bell#” 和 indices = [0, 2, 5] 。
分析:
首先对单词组words按每个单词的长度进行排序,长度依次递减,因为只有可能是长的单词合并短的单词。然后从前到后依次遍历words,如果后面有单词是当前单词的结尾的词,则将其替换为“#”,遍历完成后进行拼接。
class Solution {
public int minimumLengthEncoding(String[] words) {
Arrays.sort(words, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length()-o1.length();
}
});
for (int i = 0; i < words.length - 1; i++) {
if (words[i].equals("#")) continue;
for (int j = i+1; j < words.length; j++) {
if (words[i].endsWith(words[j])) words[j]="#";
}
}
StringBuilder ans = new StringBuilder(words[0]);
ans.append("#");
for (int i = 1; i < words.length; i++) {
if (!words[i].equals("#")) ans.append(words[i]).append("#");
}
System.out.println(ans);
return ans.toString().length();
}
}
2. 二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
分析:
使用DFS递归的搜索以每个节点为根节点的子树的最大贡献值:
- 空节点的最大贡献值等于 0。
- 非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和(对于叶节点而言,最大贡献值等于节点值)。
得到每个节点的最大贡献值之后,对于二叉树中的一个节点,该节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值,如果子节点的最大贡献值为正,则计入该节点的最大路径和,否则不计入该节点的最大路径和。维护一个全局变量 maxSum 存储最大路径和,在递归过程中更新 maxSum 的值,最后得到的 maxSum 的值即为二叉树中的最大路径和。
class Solution {
private static int max;
public int maxPathSum(TreeNode root) {
if (root == null) return 0;
max = Integer.MIN_VALUE;
roundMax(root);
return max;
}
public int roundMax(TreeNode node){
if (node == null) return 0;
int left = Math.max(roundMax(node.left),0);
int right = Math.max(roundMax(node.right),0);
max = Math.max(left+right+node.val, max);
return Math.max(left, right)+node.val;
}
}
3. 最长同值路径
给定一个二叉树的 root ,返回 最长的路径的长度 ,这个路径中的 每个节点具有相同值 。 这条路径可以经过也可以不经过根节点。
两个节点之间的路径长度 由它们之间的边数表示。
输入:root = [5,4,5,1,1,5]
输出:2
分析:
对于每一条路径来说,根是唯一的,它的父节点是不会出现在路径中的,可以把路径看作一个从当前根节点延伸出来的箭头,而箭头将是根在该路径中只有一个子节点的路径。采用递归的方法来求每个节点向左延伸的最长箭头和向右延伸的最长箭头。
令 arrow_length(node) 为从节点 node 延伸出的最长箭头的长度。如果 node.Left 存在且与节点 node 具有相同的值,则该值就会是 1 + arrow_length(node.left)。在 node.right 存在的情况下也是一样。
class Solution {
int ans;
public int longestUnivaluePath(TreeNode root) {
ans = 0;
arrowLength(root);
return ans;
}
public int arrowLength(TreeNode node) {
if (node == null) return 0;
int left = arrowLength(node.left);
int right = arrowLength(node.right);
int arrowLeft = 0, arrowRight = 0;
if (node.left != null && node.left.val == node.val) {
arrowLeft += left + 1;
}
if (node.right != null && node.right.val == node.val) {
arrowRight += right + 1;
}
ans = Math.max(ans, arrowLeft + arrowRight);
return Math.max(arrowLeft, arrowRight);
}
}