872. 叶子相似的树 / 剑指 Offer 33. 二叉搜索树的后序遍历序列 / 剑指 Offer 34. 二叉树中和为某一值的路径 / 剑指 Offer 35. 复杂链表的复制
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了872. 叶子相似的树 / 剑指 Offer 33. 二叉搜索树的后序遍历序列 / 剑指 Offer 34. 二叉树中和为某一值的路径 / 剑指 Offer 35. 复杂链表的复制相关的知识,希望对你有一定的参考价值。
872. 叶子相似的树
2021.5.10 每日一题
题目描述
请考虑一棵二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。
举个例子,如上图所示,给定一棵叶值序列为 (6, 7, 4, 9, 8) 的树。
如果有两棵二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。
如果给定的两个根结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。
输入:root1 = [3,5,1,6,2,9,8,null,null,7,4], root2 = [3,5,1,6,7,4,2,null,null,null,null,null,null,9,8]
输出:true
示例 2:
输入:root1 = [1], root2 = [1]
输出:true
示例 3:
输入:root1 = [1], root2 = [2]
输出:false
示例 4:
输入:root1 = [1,2], root2 = [2,2]
输出:true
示例 5:
输入:root1 = [1,2,3], root2 = [1,3,2]
输出:false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/leaf-similar-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
class Solution {
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
//深度优先搜索到两棵树的子节点,然后比较,想遍历过程中比较的,感觉不太行,还是存起来比较吧
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
dfs(root1, list1);
dfs(root2, list2);
if(list1.size() != list2.size())
return false;
for(int i = 0; i < list1.size(); i++){
if(list1.get(i) != list2.get(i))
return false;
}
return true;
}
public void dfs(TreeNode root, List<Integer> list){
if(root.left == null && root.right == null){
list.add(root.val);
}
if(root.left != null)
dfs(root.left, list);
if(root.right != null)
dfs(root.right, list);
}
}
剑指 Offer 33. 二叉搜索树的后序遍历序列
题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/ \\
2 6
/ \\
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
根据后序遍历的结果特点来把数组拆成左右根三个部分,然后对应的部分再进行划分,知道区间只剩下一个节点或者区间不存在
class Solution {
int[] postorder;
public boolean verifyPostorder(int[] postorder) {
//后序遍历结果,左右根,然后呢,对,还有个条件是二叉搜索树,二叉搜索树中序遍历的结果是一个递增序列
//后序遍历最后一个数字是根节点,然后小于它的是左,大于它的是右,然后再分,在判断
//好像就是这么个思路
this.postorder = postorder;
int l = postorder.length;
return helper(0, l - 1, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public boolean helper(int start, int end, int min, int max){
if(start >= end){
return true;
}
int root = postorder[end];
if(root < min || root > max)
return false;
//找到左右不分的分界点,也就是第一个大于root的点
int mid = -1;
for(int i = start; i < end; i++){
if(postorder[i] < min)
return false;
if(postorder[i] > root){
mid = i;
break;
}
}
//判断分界点后的数是否全部大于root
if(mid == -1)
mid = end;
for(int i = mid; i < end; i++){
if(postorder[i] < root || postorder[i] > max)
return false;
}
//继续判断子集
return helper(start, mid - 1, min, root - 1) && helper(mid, end - 1, root + 1, max);
}
}
看题解以后,发现写的还是麻烦,我这里加了最大最小值的限制,我认为是没问题的,但是好像没有也行?因为在每次划分左右的时候已经满足大小条件了
class Solution {
public boolean verifyPostorder(int[] postorder) {
return recur(postorder, 0, postorder.length - 1);
}
//判断i到j是否是一个二叉搜索树
public boolean recur(int[] postorder, int i, int j){
if(i >= j)
//如果只有一个节点,那么肯定是
return true;
//然后找出分界点
int m = i;
//如果小于根节点,就一直加
while(postorder[m] < postorder[j])
m++;
//到这里找到了分界点
int p = m;
//因为右子树都比根节点大
while(postorder[p] > postorder[j])
p++;
//p不等于j就说明不是
return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
}
}
剑指 Offer 34. 二叉树中和为某一值的路径
题目描述
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 target = 22,
5
/ \\
4 8
/ / \\
11 13 4
/ \\ / \\
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
深度搜索遍历每一条路径就行了,最后看路径和是否和target相同,注意因为没有给定每个节点的值的大小范围,因此不能随便剪枝
class Solution {
List<List<Integer>> res;
List<Integer> list;
public List<List<Integer>> pathSum(TreeNode root, int target) {
//又得回溯了,这里叶节点应该是叶子结点,即没有子节点的结点
res = new ArrayList<>();
list = new ArrayList<>();
recur(root, target, 0);
return res;
}
public void recur(TreeNode root, int target, int sum){
if(root == null)
return;
if(root.left == null && root.right == null){
//加起来等于target
if(sum + root.val == target){
list.add(root.val);
res.add(new ArrayList<>(list));
list.remove(list.size() - 1);
return;
}
return;
}
list.add(root.val);
recur(root.left, target, sum + root.val);
// list.remove(list.size() - 1);
// list.add(root.val);
recur(root.right, target, sum + root.val);
list.remove(list.size() - 1);
}
}
连续做了几道树的题吧,感觉对递归回溯更加熟练了,最起码自己能写出来了,是个进步,不过还得加油啊
剑指 Offer 35. 复杂链表的复制
题目描述
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
一时间没想到思路,想到的是最笨的方法,然后看到哈希表,略有所悟
class Solution {
public Node copyRandomList(Node head) {
//这个怎么做呢,第一遍遍历构建所有节点,问题是random怎么处理,难道要一个节点一个节点的处理吗
//感觉我实在是想不到更好的方法了,感觉一个个处理也很难写啊
//要找一个节点的random节点,得先找到random节点是第几个,然后再从新的链表上找到这两个节点在相互连接起来
//然后优化时间复杂度,用一个哈希表把两个对应的结点存储起来,这样在找random结点时就可以很快找到
Map<Node, Node> map = new HashMap<>();
Node newhead = new Node(-1);
//先构建普通链表
Node index = head;
Node index2 = newhead;
while(index != null){
Node temp = new Node(index.val);
index2.next = temp;
map.put(index, temp);
index = index.next;
index2 = index2.next;
}
index2.next = null;
index = head;
index2 = newhead.next;
while(index != null){
//找到random
Node ran = index.random;
index2.random = map.get(ran);
index = index.next;
index2 = index2.next;
}
return newhead.next;
}
}
第二个思路,将复制的链表节点接到对应的原链表节点后面
class Solution {
public Node copyRandomList(Node head) {
//第二种方法,巧妙的解法
//先复制链表,但是这次复制链表是将复制的结点直接加在对应的结点后面,这样做是为了方便找到random对应的结点
//然后再遍历一次链表,将对应的random连接好
//第三次遍历链表,把整个链表分开
if(head == null)
return null;
Node curr = head;
//第一步.复制链表
while(curr != null){
Node temp = new Node(curr.val);
temp.next = curr.next;
curr.next = temp;
curr = curr.next.next;
}
//第二步,处理random结点
curr = head;
while(curr != null){
if(curr.random != null){
Node temp = curr.random;
curr.next.random = curr.random.next;
}
curr = curr.next.next;
}
//第三步,分开
curr = head;
Node newhead = curr.next;
Node curr2 = head.next;
while(curr2.next != null){
curr.next = curr.next.next;
curr2.next = curr2.next.next;
curr = curr.next;
curr2 = curr2.next;
}
curr.next = null; //如果不对最后这个结点进行处理,最后两个结点还是相连状态
return newhead;
}
}
以上是关于872. 叶子相似的树 / 剑指 Offer 33. 二叉搜索树的后序遍历序列 / 剑指 Offer 34. 二叉树中和为某一值的路径 / 剑指 Offer 35. 复杂链表的复制的主要内容,如果未能解决你的问题,请参考以下文章