给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:
如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
示例:
输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<Integer> stack1 = new Stack<>();
Stack<Integer> stack2 = new Stack<>();
ListNode node1 = l1;
ListNode node2 = l2;
while(node1 != null){
stack1.push(node1.val);
node1 = node1.next;
}
while(node2 != null){
stack2.push(node2.val);
node2 = node2.next;
}
int flag = 0;
ListNode head = null;
while(!stack1.isEmpty() || !stack2.isEmpty() || flag != 0){
int value = 0;
if(!stack1.isEmpty()){
value += stack1.pop();
}
if(!stack2.isEmpty()){
value += stack2.pop();
}
value += flag;
// 构建一个新的链表结构 这里做了一个逆序的动作
// 这里必须逆序,否则就一直到了尾节点没有记忆节点,回不去
ListNode node = new ListNode(value%10);
flag = value / 10;
node.next = head;
head = node;
}
return head;
}
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reorder-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public void reorderList(ListNode head) {
// 至少三个节点
if(head == null || head.next == null) return;
// 链表排序 1 2 3 4 | 1 4 2 3
// L0 Ln L1 Ln-1 ......
// 使用快慢指针算出终点
ListNode fast = head;
ListNode slow = head;
while(fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
}
// slow到了中点
fast = slow.next;
slow.next = null;
// 指向头部
slow = head;
// 链表翻转 翻转一半的链表
ListNode next2;
ListNode head2 = fast;
while(fast.next != null){
next2 = fast.next;
fast.next = next2.next;
next2.next = head2;
head2 = next2;
}
fast = head2;
// 链表组合
ListNode next1;
while(fast != null){
next1 = slow.next;
next2 = fast.next;
slow.next = fast;
fast.next = next1;
fast = next2;
slow = next1;
}
}
给定一个链表(链表结点包含一个整型值)的头结点 head。
同时给定列表 G,该列表是上述链表中整型值的一个子集。
返回列表 G 中组件的个数,这里对组件的定义为:链表中一段最长连续结点的值(该值必须在列表 G 中)构成的集合。
示例 1:
输入:
head: 0->1->2->3
G = [0, 1, 3]
输出: 2
解释:
链表中,0 和 1 是相连接的,且 G 中不包含 2,所以 [0, 1] 是 G 的一个组件,同理 [3] 也是一个组件,故返回 2。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-components
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/*
题目的意思是找最长的组件个数,意思就是每次G中这个数没有就要计数+1或者停顿就要计数+1
*/
public int numComponents(ListNode head, int[] G) {
int num = 0;
boolean[] A = new boolean[10000];
for (int i : G) {
A[i] = true;
}
ListNode cur = head;
while(cur != null){
if(A[cur.val]){
// 一直遍历到最后的话,就加一
// 不是一直到最后的话,也是取的最长的组件。
// 每次停顿必加一
while(cur.next != null && A[cur.next.val]){
cur = cur.next;
}
num ++;
}
cur = cur.next;
}
return num;
}
给定一个头结点为 root 的链表, 编写一个函数以将链表分隔为 k 个连续的部分。
每部分的长度应该尽可能的相等: 任意两部分的长度差距不能超过 1,也就是说可能有些部分为 null。
这k个部分应该按照在链表中出现的顺序进行输出,并且排在前面的部分的长度应该大于或等于后面的长度。
返回一个符合上述规则的链表的列表。
举例: 1->2->3->4, k = 5 // 5 结果 [ [1], [2], [3], [4], null ]
示例 1:
输入:
root = [1, 2, 3], k = 5
输出: [[1],[2],[3],[],[]]
解释:
输入输出各部分都应该是链表,而不是数组。
例如, 输入的结点 root 的 val= 1, root.next.val = 2, \root.next.next.val = 3, 且 root.next.next.next = null。
第一个输出 output[0] 是 output[0].val = 1, output[0].next = null。
最后一个元素 output[4] 为 null, 它代表了最后一个部分为空链表。
示例 2:
输入:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
输出: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过1.前面部分的长度大于等于后面部分的长度。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/split-linked-list-in-parts
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public ListNode[] splitListToParts(ListNode root, int k) {
// 1 2 3 | 5 [[1],[2],[3],[],[]];
ListNode[] head = new ListNode[k];
// 第一遍遍历看长度是否大于k,不大于,后面部分直接置为0
int cnt = 0;
ListNode cur = root;
while(cur != null){
cnt += 1;
cur = cur.next;
}
cur = root;
// 长度小于或者等于k的情况
if(cnt <= k){
for (int i = 0; i < k; i++) {
if(cur != null){
head[i] = new ListNode(cur.val);
cur = cur.next;
}else {
head[i] = null;
}
}
}else{
// 长度大于k的情况,此时涉及到分组,如何去分组!!
// 先用长度cnt/k=初始个数,cnt/k=多出来的个数
int initLen = cnt / k;
int extraLen = cnt % k;
int[] len = new int[k];
// 分配最基本的长度 多出来的长度如果不为0则加一
for (int i = 0; i < k; i++) {
len[i] = extraLen-- > 0 ? initLen+1 : initLen;
}
// 数组已经分配好了 一定要判断cur != null否则无法进行,会报空指针异常
for (int i = 0; i < k && cur != null; i++) {
head[i] = cur;
// 从1开始是因为cur一开始就在1的位置,如果从0链表会多走一步
for (int j = 0; j < len[i]-1; j++) {
cur = cur.next;
}
// 截断链表
ListNode temp = cur.next;
cur.next = null;
cur = temp;
}
}
return head;
}
// 优化的算法:借鉴的,不需要判断,因为长度小压根没法进入循环,直接也就是null
public ListNode[] splitListToParts(ListNode root, int k) {
int n = 0;
ListNode cur = root;
while(cur != null){
n++;
cur = cur.next;
}
int mod = n % k;
int size = n / k;
ListNode [] res = new ListNode[k];
cur = root;
for (int i = 0; i < k && cur != null; i++){
res[i] = cur;
// 当前长度,如过为0,直接跳过,妙!
int cursize = size + (mod-- > 0 ? 1 : 0);
for (int j = 0; j < cursize - 1; j++){
cur = cur.next;
}
ListNode next = cur.next;
cur.next = null;
cur = next;
}
return res;
}
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public ListNode partition(ListNode head, int x) {
if(head == null || head.next == null) return head;
// 不需要排序!!!
// 两个链,一个链表连接小于3
ListNode dummyNode1 = new ListNode(0);
ListNode p1 = dummyNode1;
// 一个链表连接大于等于3
ListNode dummyNode2 = new ListNode(0);
ListNode p2 = dummyNode2;
ListNode cur = head;
while(cur != null){
if(cur.val < x){
p1.next = cur;
p1 = p1.next;
}else{
p2.next = cur;
p2 = p2.next;
}
cur = cur.next;
}
// 组合起来就好
p2.next = null;
p1.next = dummyNode2.next;
return dummyNode1.next;
}
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public ListNode reverseBetween(ListNode head, int m, int n) {
// 道理都懂就是翻译不成代码 图没画全,指针可以进两个,但是出只能出一个,而且后出的会覆盖之前的。
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
for(int i=0; i < m-1; i++) pre = pre.next;// 确定第一个节点
ListNode node = null;
ListNode cur = pre.next;
// 直接反转
for (int i = 0; i < n-m+1 ; i++) {
ListNode temp = cur.next;
cur.next = node;
node = cur;
cur = temp;
}
// 1-> 2 <- 3 <- 4 -> 5 链表拼接
pre.next.next = cur;
pre.next = node;
return dummyNode.next;
}
public ListNode reverseBetween2(ListNode head, int m, int n) {
// 1 2 3 4 5 插在1 2之间
// 1 3 2 4 5 插在1 3之间
// 1 4 3 2 5 结束
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode pre = dummyNode;
for(int i=0; i < m-1; i++) pre = pre.next;// 第一个指针
ListNode p1 = pre.next;
ListNode p2 = p1.next;
for(int i=0; i< n-m; i++){
p1.next = p2.next;
p2.next = pre.next;// 用pre是因为pre是恒定不变的,只有用pre才能保证一定是插在这个位置上
pre.next = p2;
p2 = p1.next;
}
return dummyNode.next;
}
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public static ListNode rotateRight(ListNode head, int k) {
if(head == null || head.next == null) return head;
// 其实就是链表的移位
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode cur = dummyNode;
ListNode res = head;
int num = 0;
while(res.next.next != null){
num += 1;
res = res.next;
}
num += 1;
// res到达尾节点
// 0 1 2 3 4 5 无论移动多少次,都是一直在往0后面插入
// 永远保证最后一个节点一直在往前插!必须一直往前进
ListNode p1 = res;
ListNode p2 = p1.next;
int n = k%num;
while(n-- > 0){
p1.next = p2.next;
p2.next = cur.next;
cur.next = p2;
while(p2.next != p1){
p2 = p2.next;
}
p1 = p2;
p2 = p2.next;
}
return dummyNode.next;
}
// 第二种方法,快慢指针
public static ListNode rotateRight2(ListNode head, int k) {
if(head == null || head.next == null) return head;
// 快慢指针解决
ListNode fast = head, slow = head, cur = head;
// 统计个数
int len = 0;
while(cur != null){
cur = cur.next;
len++;
}
// 真正需要移动的位数
k = k % len;
// 说到底就是找到K次之后的新头结点的前一个节点即可
// 利用slow和fast之间差距k个节点来的
while(k > 0){
fast = fast.next;
if(fast == null)
fast = head;
k--;
}
// 这是在寻找新的尾节点
while(fast.next != null){
slow = slow.next;
fast = fast.next;
}
// 如果slow和fast同时到达尾部,则k相当于没变化,直接返回head
if(slow.next == null)
return head;
// 做一个拼接1 2 3 4 5
// fast在5处,slow在3处,
// 拼接起来
ListNode oldTail = fast, tail = slow, newHead = tail.next;
tail.next = null;
oldTail.next = head;
return newHead;
}
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public static ListNode reverseKGroup(ListNode head, int k) {
// 判断边界,如果head为空或者只有一个元素或者k为1则直接返回
if(head == null || head.next == null || k==1) return head;
// 设置dummyNode,用于链表翻转
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode res = dummyNode;
// 计算多少个节点
ListNode cur = head;
int num = 0;
while(cur != null){
num += 1;
cur = cur.next;
}
int cnt = num / k; // 翻转几次
// 用作翻转的节点
ListNode p1 = res.next;
ListNode p2 = p1.next;
int temp = k;
while(cnt-- > 0){
// 链表的插入
while(--temp > 0){
p1.next = p2.next;
p2.next = res.next;
res.next = p2;
p2 = p1.next;
}
res = p1;
// 如果翻转完直接到了末尾,则break结束
if(p1.next == null){
break;
}else {
// 否则将这个点作为第一个点,用于插入新的节点在其之间
p1 = p1.next;
p2 = p1.next;
// temp还是要等于k,注意还原
temp = k;
}
}
// 返回结果
return dummyNode.next;
}
}
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public static ListNode removeNthFromEnd(ListNode head, int n) {
if (head == null) return head;
ListNode cur = head;
// 人为构造节点
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode res = dummyNode;
// 计算节点个数
int cnt = 1;// 包括人为构造的头结点
while(cur != null){
cnt += 1;
cur = cur.next;
}
int num = 0;// 计数到达第几个就停止
while(res != null){
num += 1;
// 从倒数变为正数
if (num == cnt - n){
// 删除节点
ListNode temp = res.next;
res.next = res.next.next;
temp.next = null;
break;
}else {
res = res.next;
}
}
return dummyNode.next;
}
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 第一种方法自己写的,方法很繁琐,结果很简单。时间复杂度很高。
public static ListNode deleteDuplicates2(ListNode head) {
if(head == null || head.next == null) return head;
ListNode dummyNode = new ListNode(Integer.MAX_VALUE);
dummyNode.next = head;
ListNode res = dummyNode;
ListNode cur = res.next;
while(cur.next != null){
if(cur.val == cur.next.val){
// 找到重复元素的最后一个节点
ListNode temp = cur.next;
if(temp.next != null){
while(temp.next != null && temp.val == temp.next.val){
temp = temp.next;
}
}
// 找到cur前一个节点
while(res.next != cur){
res = res.next;
}
// 此时交换位置
res.next = temp.next;
temp.next = null;
res = dummyNode;
cur = res.next;
if(cur == null){
break;
}
}else{
cur = cur.next;
}
}
return dummyNode.next;
}
// 第二种方法:参照别人的,比较简单,使用递归
public static ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null) return head;
if(head.next != null && head.val == head.next.val){
while(head.next != null && head.val == head.next.val){
head = head.next;
}
// 不等就从下一个开始
return deleteDuplicates(head.next);
}else{
// 不等就从下一个开始
head.next = deleteDuplicates(head.next);
}
return head;
}
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public ListNode mergeKLists1(ListNode[] lists) {
// N个有序链表排序
// 暴力法
List<Integer> res = new ArrayList<>();
for (ListNode list : lists) {
while(list != null){
res.add(list.val);
list = list.next;
}
}
// 取出来排序
Collections.sort(res);
ListNode dummyNode = new ListNode(0);
ListNode cur = dummyNode;
// 重整链表
for (int i = 0; i < res.size(); i++) {
cur.next = new ListNode(res.get(i));
cur = cur.next;
}
return dummyNode.next;
}
//---------------------第二种方法
public ListNode mergeKLists(ListNode[] lists) {
// 使用归并排序
if (lists == null || lists.length == 0) return lists[0];
return merge(lists, 0, lists.length - 1);
}
public ListNode merge(ListNode[] list, int left, int right){
// 归并
if(left == right) return list[left];
int m = left + (right - left)/2;
ListNode l1 = merge(list,left,m);
ListNode l2 = merge(list,m+1,right);
return mergeListNode(l1,l2);
}
public static ListNode mergeListNode(ListNode l1, ListNode l2){
// 递归方式
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val){
l1.next = mergeListNode(l1.next,l2);
return l1;
}else{
l2.next = mergeListNode(l2.next,l1);
return l2;
}
}
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1
/ \ /
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入: 1 1
/
2 2
[1,2], [1,null,2]
输出: false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/same-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public boolean isSameTree1(TreeNode p, TreeNode q) {
// 判断两棵树是否是相同的数,结构相同,值也相同
// 树就是递归的完美体现
// 递归需要一个终止条件
if(p != null && q != null){
if(p.val != q.val){
return false;
}else{
// return isSameTree1(p.left, q.left) ? (isSameTree1(p.right, q.right)==true ? true : false) : false ;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}else if(p!= null && q==null || p == null && q != null){
return false;
}
return true;
}
//-----------------------官方题解----------------------
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
if(p == null || q == null) return false;
if(p.val != q.val) return false;
return isSameTree(p.left, q.left) && isSameTree(p.right,q.right);
}
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public TreeNode sortedArrayToBST(int[] nums) {
return rebuildTree(nums, 0, nums.length - 1);
}
public TreeNode rebuildTree(int[] nums, int l, int r){
if(l > r) return null;// 防止长度为0出现
int m = (l+r)>>1;
TreeNode root = new TreeNode(nums[m]);
root.left = rebuildTree(nums,l,m-1);
root.right = rebuildTree(nums, m+1, r);
return root;
}
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int maxDepth1(TreeNode root) {
if(root == null){
return 0;
}else{
int left_height = maxDepth(root.left);
int right_height = maxDepth(root.right);
return Math.max(left_height,right_height)+1;
}
}
// -------------自己的好累赘---------------------
public int maxDepth(TreeNode root) {
int num = 0;
if(root == null){
return num;
}else{
num += 1;
}
int num1 = 0;
int num2 = 0;
// 左边高度
if(root.left != null){
num1 += maxDepth(root.left);
}
// 右边高度
if(root.right != null){
num2 += maxDepth(root.right);
}
return num+Math.max(num1,num2);
}
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
返回 true 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/balanced-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// ---------------------自顶向下-时间复杂度O(n^2)--------------------
public boolean isBalanced(TreeNode root) {
// 算高度,只要高度之差大于1直接false;
// 这只是配判断整体,它要将左右作为一个整体
if(Math.abs(maxDepth(root.left) - maxDepth(root.right)) > 1){
return false;
}
// 这里用递归判断左右节点,每一个左右节点都要单独拎出来判断
return isBalanced(root.left) && isBalanced(root.right);
}
public int maxDepth(TreeNode root) {
// 最大深度
if(root == null){
return 0;
}else{
int left_height = maxDepth(root.left);
int right_height = maxDepth(root.right);
return Math.max(left_height, right_height)+1;
}
}
// ----------------------自底向上-时间复杂度O(n)-----------------------
// 设置的全局标志
boolean res = true;
public boolean isBalanced(TreeNode root) {
depth(root);
return res;
}
public int depth(TreeNode root){
if(root == null) return 0;
int left = depth(root.left) + 1;
int right = depth(root.right) + 1;
if(Math.abs(left - right) > 1) res = false;
return Math.max(left, right);
}
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3
说明:
如果你可以运用递归和迭代两种方法解决这个问题,会很加分。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/symmetric-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 实质就是将左右子树对比看左子树的左节点是否等于右子树的右节点,左子树右节点是否等于右子树左节点
// 拆分成两颗树,只要两棵树递归的时候左等于右即可
public boolean isSymmetric(TreeNode root) {
// 判断是不是镜像对称的树
if(root != null){
return isMirror(root.left,root.right);
}
return true;
}
// 判断是否是镜像
public boolean isMirror(TreeNode a, TreeNode b){
if(a==null && b==null) return true;
if(a == null || b == null) return false;
return (a.val == b.val) && isMirror(a.left, b.right) && isMirror(a.right, b.left);
}
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 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/path-sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 这一题对于自己来说有点难度
// 主要的思路:用一个总了来存储,用一个list来存每一次的,先一直向左,满足就添加,不满足则采用回溯,然后往右
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> resList = new ArrayList<>();
addList(root,sum,resList,new ArrayList<>());
return resList;
}
public void addList(TreeNode root, int sum, List<List<Integer>> resList, ArrayList<Integer> list){
if(root == null) return;
list.add(root.val);
if(root.left == null && root.right == null && root.val - sum == 0){
// 复用,需要使用new ArrayList<>(list)
resList.add(new ArrayList<>(list));
}
// 一直往左,有就添加,没有就回溯,然后往右
addList(root.left,sum - root.val, resList, list);
addList(root.right, sum - root.val, resList, list);
list.remove(list.size() - 1);
}
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/path-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public boolean hasPathSum(TreeNode root, int sum) {
// 为null直接返回false
if(root == null) return false;
// 不为null,判断sum-当前节点是否为0且此节点的左右子节点是否都为null
if(root != null){
// 满足则true
if(sum - root.val == 0 && root.left == null && root.right == null) {
return true;
}
}
return hasPathSum(root.left,sum - root.val) || hasPathSum(root.right,sum - root.val);
}
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最小深度 2.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int minDepth(TreeNode root) {
if(root == null) return 0;
// 返回1
if(root.left == null && root.right == null) return 1;
int min_depth = Integer.MAX_VALUE;
// 值求最小深度
if(root.left != null){
min_depth = Math.min(min_depth,minDepth(root.left));
}
if(root.right != null){
min_depth = Math.min(min_depth,minDepth(root.right));
}
// 加上第一个
return min_depth + 1;
}
翻转一棵二叉树。
示例:
输入:
4
/
2 7
/ \ /
1 3 6 9
输出:
4
/
7 2
/ \ /
9 6 3 1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/invert-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public TreeNode invertTree(TreeNode root) {
if(root == null) return null;
// 交换,一定要注意,值交换不能实现
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 注意这是一颗二叉搜索树,利用二叉搜索树的性质,左边的小于根节点,右边的大于根节点
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
int parentVal = root.val;
int pVal = p.val;
int qVal = q.val;
if(pVal > parentVal && qVal > parentVal){
return lowestCommonAncestor(root.right,p,q);
}else if(pVal < parentVal && qVal < parentVal){
return lowestCommonAncestor(root.left,p,q);
}else{
return root;
}
}
// 当此树为任意数时,下面的方法也可以查找到。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 找两者共同的祖先节点,可以是节点自身
if(root == null) return null;
if(root.val == p.val || root.val == q.val) {
return root.val == p.val ? p : q;
}
if(isTrue(root.left,p) && isTrue(root.left,q)){
return lowestCommonAncestor(root.left,p,q);
}
if(isTrue(root.right,p) && isTrue(root.right, q)){
return lowestCommonAncestor(root.right,p,q);
}
return root;
}
public boolean isTrue(TreeNode root, TreeNode test){
if(root == null) return false;
return root.val == test.val || isTrue(root.left,test) || isTrue(root.right,test);
}
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入:
1
/
2 3
5
输出: [“1->2->5”, “1->3”]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-paths
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public List<String> binaryTreePaths(TreeNode root) {
List<String> list = new ArrayList<>();
constructPaths(list,root,"");
return list;
}
// 只加入左右节点均为null的节点
public void constructPaths(List<String> list, TreeNode root, String path){
if(root == null) {
return;
}else{
path += root.val;
if(root.left == null && root.right == null) list.add(path);
path += "->";
constructPaths(list, root.left, path);
constructPaths(list,root.right, path);
}
}
计算给定二叉树的所有左叶子之和。
示例:
3
/
9 20
/
15 7
在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-left-leaves
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int sumOfLeftLeaves(TreeNode root) {
int num = 0;
if(root == null) return 0;
if(root.left != null) {
// 必须为叶子节点
if(root.left.left == null && root.left.right == null){
num += root.left.val;
}else {
num += root.left.val + sumOfLeftLeaves(root.left);
}
}
if(root.right != null) {
num += sumOfLeftLeaves(root.right);
}
return num;
}
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
示例:
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 的路径有:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/path-sum-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int pathSum(TreeNode root, int sum) {
if(root == null) return 0;
return countNum(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
}
public int countNum(TreeNode root, int sum){
if(root == null) return 0;
// 其实就是实现双重递归
sum -= root.val;
return (sum == 0 ? 1 : 0) + countNum(root.left, sum) + countNum(root.right, sum);
}
//---------------------------------区间值相等即可-------------------------------------------
public int pathSum(TreeNode root, int sum) {
if(root == null) return 0;
HashMap<Integer, Integer> map = new HashMap<>();
// 默认如果为0就为1
map.put(0,1);
return helper(root,map,sum,0);
}
public int helper(TreeNode root, HashMap<Integer,Integer> map, int sum, int num){
int res = 0;
if(root == null) return 0;
num += root.val;
res += map.getOrDefault(num - sum, 0);
// 表示如果在map中有这个key则取出这个key的值,否则娶defaultValue
map.put(num, map.getOrDefault(num, 0) + 1);
// 左边和右边
res += helper(root.left,map,sum,num) + helper(root.right, map, sum, num);
// 左边进来的时候num为这个,右边进来也为这个值
map.put(num, map.get(num) - 1);
return res;
}
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
结点左子树中所含结点的值小于等于当前结点的值
结点右子树中所含结点的值大于等于当前结点的值
左子树和右子树都是二叉搜索树
例如:
给定 BST [1,null,2,2],
1
2
/
2
返回[2].
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
List<Integer> list = new ArrayList<>();
int max = 0;
int cur = 1;
TreeNode pre;// 借助一个临时节点来移动自己
public int[] findMode(TreeNode root) {
if(root == null) return new int[]{};
inorder(root);
int[] res = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
res[i] = list.get(i);
}
return res;
}
public void inorder(TreeNode root){
if(root == null) return;
// 走左边的
inorder(root.left);
// 判断值相不相等
if(pre != null){
// 相等继续加一
if(pre.val == root.val){
cur += 1;
}else{
// 否则为1
cur = 1;
}
}
// 遇到相同个数,加进list中
if(cur == max){
list.add(root.val);
}
// 遇到更大的,清空list,然后加入当前节点,最大值变为现在的节点
if(cur > max){
list.clear();
list.add(root.val);
max = cur;
}
// 节点移动
pre = root;
// 移动到右边
inorder(root.right);
}
给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值。
示例 :
输入:
1
3
/
2
输出:
1
解释:
最小绝对差为1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。
注意: 树中至少有2个节点。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
TreeNode pre = null;
int minNum = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
// 不可能为空,至少存在两个节点
// 计算的是所有节点之间的最小值
helper(root);
return minNum;
}
public void helper(TreeNode root){
if(root == null) return;
// 二叉搜索树一定要注意从左侧开始
helper(root.left);
if(pre != null){
minNum = Math.min((pre.val - root.val),minNum);
}
pre = root;
helper(root.right);
}
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。
例如:
输入: 二叉搜索树:
5
/
2 13
输出: 转换为累加树:
18
/
20 13
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-bst-to-greater-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
TreeNode pre = null;
public TreeNode convertBST(TreeNode root) {
if(root == null) return null;
sum(root);
return root;
}
public void sum(TreeNode root){
if(root == null) return;
// 先右边就好
sum(root.right);
if(pre != null){
root.val += pre.val;
}
pre = root;
sum(root.left);
}
给定一个二叉树,计算整个树的坡度。
一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。
整个树的坡度就是其所有节点的坡度之和。
示例:
输入:
1
/
2 3
输出: 1
解释:
结点的坡度 2 : 0
结点的坡度 3 : 0
结点的坡度 1 : |2-3| = 1
树的坡度 : 0 + 0 + 1 = 1
注意:
任何子树的结点的和不会超过32位整数的范围。
坡度的值不会超过32位整数的范围。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-tilt
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
int tiltSum = 0;
public int findTilt(TreeNode root) {
if(root == null) return 0;
tilt(root);
return tiltSum;
}
public int tilt(TreeNode root){
if(root == null) return 0;
int l = tilt(root.left);
int r = tilt(root.right);
tiltSum += Math.abs(l-r);
return l+r+root.val;
}
// 坡度在计算,但是和需要累加到节点上再计算!
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
示例 1:
给定的树 s:
3
/ \
4 5
/
1 2
给定的树 t:
4
/
1 2
返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subtree-of-another-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public boolean isSubtree(TreeNode s, TreeNode t) {
if(s == null && t == null) return true;
if(s == null || t == null) return false;
if(s.val == t.val){
// 判断是否全等,不是全等的话,看看是不是左子树,或者是右子树
return isEqual(s,t) || isSubtree(s.left,t) || isSubtree(s.right, t);
}
// 如果根节点就不相等,直接判断左子树和右子树
return isSubtree(s.left, t) || isSubtree(s.right, t);
}
// 判断是否全等
public boolean isEqual(TreeNode s, TreeNode t){
if(s == null && t == null) return true;
if(s == null || t == null) return false;
if(s.val == t.val){
return isEqual(s.left, t.left) && isEqual(s.right, t.right);
}
return false;
}
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 “()” 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
示例 1:
输入: 二叉树: [1,2,3,4]
1
/
2 3
/
4
输出: “1(2(4))(3)”
解释: 原本将是“1(2(4)())(3())”,
在你省略所有不必要的空括号对之后,
它将是“1(2(4))(3)”。
示例 2:
输入: 二叉树: [1,2,3,null,4]
1
/
2 3
\
4
输出: “1(2()(4))(3)”
解释: 和第一个示例相似,
除了我们不能省略第一个对括号来中断输入和输出之间的一对一映射关系。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-string-from-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 自己写的,时间复杂度和空间复杂度都比较高,可能是递归用的太粗粒度
public String tree2str(TreeNode t) {
StringBuilder sb = new StringBuilder();
if(t == null) return "";
sb.append(t.val);
// 左边不为空的话,则左边递归,右边根据是否为空选择是否需要递归
if(t.left != null){
sb.append("("+tree2str(t.left)+")");
sb.append(t.right == null ? "" : "("+tree2str(t.right)+")");
// 如果左边为空右边不为空的话,则进行处理
// 如果左右都为空的话,不需要进行处理
}else if(t.left == null && t.right != null){
sb.append("()");
sb.append("("+tree2str(t.right)+")");
}
return sb.toString();
}
// 参照人家的解法,其实意思差不多,不过递归粒度更细,时间空间复杂度也更低
public String tree2str(TreeNode t) {
StringBuilder sb = new StringBuilder();
if(t == null) return sb.toString();
helper(t, sb);
return sb.toString();
}
private void helper(TreeNode t, StringBuilder sb) {
if(t == null) return;
sb.append(t.val);
if(t.left != null){
sb.append("(");
helper(t.left, sb);
sb.append(")");
}else{
if(t.right != null){
sb.append("()");
}
}
if(t.right != null){
sb.append("(");
helper(t.right, sb);
sb.append(")");
}
}
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-binary-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 思路很简单,只需要没有左就返回右,没有右返回左,两者都没有,构造新节点
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if(t1 == null) return t2;
if(t2 == null) return t1;
// 如果两者都不为null,构造一个新的节点
TreeNode res = new TreeNode(t1.val + t2.val);
// 只需要返回新的节点就行
res.left = mergeTrees(t1.left, t2.left);
res.right = mergeTrees(t1.right, t2.right);
return res;
}
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.
示例 1:
输入:
3
/
9 20
/
15 7
输出: [3, 14.5, 11]
解释:
第0层的平均值是 3, 第1层是 14.5, 第2层是 11. 因此返回 [3, 14.5, 11].
注意:
节点值的范围在32位有符号整数范围内。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/average-of-levels-in-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 有时候需要打破惯性思维!不能觉得在做树的题目,就全是利用递归
// 问题按照原先的思路解决不了的时候,可以回头看看!
public List<Double> averageOfLevels(TreeNode root) {
List<Double> list = new ArrayList<>();
if(root == null) return list;
// 利用队列来存储当前节点
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
// 当前节点的个数
int size = queue.size();
double ave = 0;
for (int i = 0; i < size; i++) {
// 通过遍历存储下一次需要计算的节点个数
TreeNode node = queue.poll();
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
// 将值存储起来
ave += node.val;
}
// 计算并加入到list中
list.add(ave/size);
}
return list;
}
给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
案例 1:
输入:
5
/
3 6
/ \
2 4 7
Target = 9
输出: True
案例 2:
输入:
5
/
3 6
/ \
2 4 7
Target = 28
输出: False
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 第一种方法,利用set存储,然后看是否包含,时间复杂度O(N),空间复杂度O(N)
Set<Integer> set = new HashSet<>();
public boolean findTarget(TreeNode root, int k) {
if(root == null) return false;
if(set.contains(root.val)){
return true;
}else{
set.add(k - root.val);
}
return findTarget(root.left,k) || findTarget(root.right,k);
}
// 第二种方法利用BST树的特性,左边小于中间节点,右边大于中间节点,时间复杂度O(nlongn),空间复杂度O(1)
public boolean findTarget(TreeNode root, int k) {
if(root == null) return false;
// 使用的是前序遍历
return preOrder(root, root, k);
}
public TreeNode findV(TreeNode node, int v){
if(node == null) return null;
if(node.val == v) return node;
// 特性,左边小,右边大
if(v < node.val) return findV(node.left,v);
else return findV(node.right,v);
}
public boolean preOrder(TreeNode node,TreeNode root,int k){
if (node == null) return false;
int target = k - node.val;
TreeNode foundNode = findV(root,target);
// 去除重复的点,就是防止自己等于自己
if(foundNode != null && node != foundNode) return true;
else{
return preOrder(node.left,root, k) || preOrder(node.right,root,k);
}
}
给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
示例 1:
输入:
1
/
0 2
L = 1
R = 2
输出:
1
2
示例 2:
输入:
3
/
0 4
2
/
1
L = 1
R = 3
输出:
3
/
2
/
1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trim-a-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public TreeNode trimBST(TreeNode root, int L, int R) {
if(root == null) return null;
// 大于最大的,只能是在左边
if(root.val > R){
return trimBST(root.left,L,R);
}
// 小于最小的,只能是在右边
if(root.val < L){
return trimBST(root.right,L,R);
}
// 左右递归
root.left = trimBST(root.left, L, R);
root.right = trimBST(root.right, L, R);
return root;
}
// -------------时间复杂度和空间复杂度都高,投机取巧的办法,不建议---------------
List<Integer> list = new ArrayList<>();
public int findSecondMinimumValue(TreeNode root) {
getList(root);
HashSet<Integer> set = new HashSet<>(list);
if(set.size() == 1){
return -1;
}
list = new ArrayList<>(set);
Collections.sort(list);
return list.get(1);
}
public void getList(TreeNode root){
if(root == null) return;
list.add(root.val);
getList(root.left);
getList(root.right);
}
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。
示例 1:
输入:
2
/
2 5
/
5 7
输出: 5
说明: 最小的值是 2 ,第二小的值是 5 。
示例 2:
输入:
2
/
2 2
输出: -1
说明: 最小的值是 2, 但是不存在第二小的值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/second-minimum-node-in-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int findSecondMinimumValue(TreeNode root) {
int smin = -1;
if(root == null) return smin;
int min = root.val;
smin = helper(root,min,smin);
return smin;
}
public int helper(TreeNode root, int min, int smin){
if(root == null) return smin;
// 只有第一次才给第二大的值赋值
if(root.val > min && smin == -1){
smin = root.val;
}
// 其余的只有满足这种条件,否则不交换,这是为了保证smin一直是第二小
if(root.val > min && root.val < smin){
smin = root.val;
}
smin = helper(root.left, min, smin);
smin = helper(root.right, min, smin);
return smin;
}
给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:两个节点之间的路径长度由它们之间的边数表示。
示例 1:
输入:
5
/ \
4 5
/ \ \
1 1 5
输出:
2
示例 2:
输入:
1
/ \
4 5
/ \ \
4 4 5
输出:
2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-univalue-path
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
int res = 0;
public int longestUnivaluePath2(TreeNode root) {
helper(root);
return res;
}
public int helper(TreeNode root){
if(root == null) return 0;
int left = helper(root.left);
int right = helper(root.right);
// 从根节点一直遍历到最左最右,然后进行处理,直接返回两边相加与res的对比
// 往上走,因为路径不能左边加右边加,所以返回左右最大的
int l = 0; int r = 0;
if(root.left != null && root.val == root.left.val){
l += left + 1;
}
if(root.right != null && root.val == root.right.val){
r += right + 1;
}
res = Math.max(res, l+r);
// 往上走只能返回单边的
return Math.max(l,r);
}
给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
例如,给定一个 3叉树 :
返回其层序遍历:
[
[1],
[3,2,4],
[5,6]
]
说明:
树的深度不会超过 1000。
树的节点总数不会超过 5000。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
helper(root, 0, res);
return res;
}
public void helper(Node root, int depth, List<List<Integer>> res) {
if (root == null) return;
// 是在往下走,可是每一层会放一个空的list,根据深度来添加
if (depth + 1 > res.size()) {
res.add(new ArrayList<>());
}
res.get(depth).add(root.val);
// 递归
for (Node child : root.children) {
if (child != null) {
helper(child, depth + 1, res);
}
}
}
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
例如,给定一个 3叉树 :
我们应返回其最大深度,3。
说明:
树的深度不会超过 1000。
树的节点总不会超过 5000。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 每节点的每一层进行比较即可
public int maxDepth(Node root) {
if (root == null) return 0;
int max = 0;
for (Node child : root.children) {
if (child != null) {
// 其实只是比较了一个节点
int depth = maxDepth(child);
max = Math.max(max, depth);
}
}
return max + 1;
}
给定一个 N 叉树,返回其节点值的前序遍历。
例如,给定一个 3叉树 :
返回其前序遍历: [1,3,5,6,2,4]。
说明: 递归法很简单,你可以使用迭代法完成此题吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 递归法
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
helper(root, res);
return res;
}
public void helper(Node root, List<Integer> res) {
if (root == null) return;
res.add(root.val);
for (Node child : root.children) {
helper(child, res);
}
}
// 迭代法 借助栈结构来解决
public List<Integer> preOrder(Node root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
Node cur = stack.pop();
res.add(cur.val);
List<Node> children = cur.children;
for (int i = children.size() - 1; i <= 0; i++) {
stack.push(children.get(i));
}
}
return res;
}
给定一个 N 叉树,返回其节点值的后序遍历。
例如,给定一个 3叉树 :
返回其后序遍历: [5,6,3,2,4,1].
说明: 递归法很简单,你可以使用迭代法完成此题吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
// 使用一个临时节点
Node pre = null;
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
Node cur = stack.peek();
// 当子节点为空的时候,或者pre有值的时候且当前的子节点包含pre,可以断定pre已经加入了运算
// pre逐渐往前走,直到结束
if (cur.children.size() == 0 || (pre != null && cur.children.contains(pre))) {
res.add(cur.val);
stack.pop();
pre = cur;
} else {
List<Node> childList = cur.children;
for (int i = childList.size() - 1; i >= 0; i--) {
stack.push(childList.get(i));
}
}
}
return res;
}
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
例如,
给定二叉搜索树:
4
/ \
2 7
/ \
1 3
和值: 2
你应该返回如下子树:
2
/ \
1 3
在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-a-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 没有用到二叉搜索树的性质,相对时间复杂度高一些
public TreeNode searchBST(TreeNode root, int val) {
if(root == null) return null;
if(root.val == val) return root;
TreeNode left = searchBST(root.left, val);
TreeNode right = searchBST(root.right,val);
if(left==null && right == null){
return null;
}
return left == null ? right : left;
}
//------------------------------------------------------------------
public TreeNode searchBST(TreeNode root, int val) {
if(root == null) return null;
if(root.val == val) return root;
// 因为是二叉搜索树,所以还可以继续优化
if(root.val > val){
TreeNode left = searchBST(root.left, val);
return left;
}else{
TreeNode right = searchBST(root.right,val);
return right;
}
}
给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。
示例:
输入: root = [4,2,6,1,3,null,null]
输出: 1
解释:
注意,root是树结点对象(TreeNode object),而不是数组。
给定的树 [4,2,6,1,3,null,null] 可表示为下图:
4
/ \
2 6
/ \
1 3
最小的差值是 1, 它是节点1和节点2的差值, 也是节点3和节点2的差值。
注意:
二叉树的大小范围在 2 到 100。
二叉树总是有效的,每个节点的值都是整数,且不重复。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
int min = Integer.MAX_VALUE;
int res = Integer.MAX_VALUE;
public int minDiffInBST(TreeNode root) {
helper(root);
return min;
}
public void helper(TreeNode root) {
if (root == null) return;
// 左
helper(root.left);
if(res != Integer.MAX_VALUE){
min = Math.min(min, root.val - res);
}
// 中间临时节点
res = root.val;
// 右
helper(root.right);
}
请考虑一颗二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。
举个例子,如上图所示,给定一颗叶值序列为 (6, 7, 4, 9, 8) 的树。
如果有两颗二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。
如果给定的两个头结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。
提示:
给定的两颗树可能会有 1 到 100 个结点。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/leaf-similar-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 深度遍历~
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
List<Integer> list1 = new ArrayList<>();
getList(root1,list1);
List<Integer> list2 = new ArrayList<>();
getList(root2,list2);
return list1.equals(list2);
}
public void getList(TreeNode root, List<Integer> list) {
if (root == null) return;
if (root.left == null && root.right == null) {
list.add(root.val);
}
getList(root.left, list);
getList(root.right, list);
}
给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和。
二叉搜索树保证具有唯一的值。
示例 1:
输入:root = [10,5,15,3,7,null,18], L = 7, R = 15
输出:32
示例 2:
输入:root = [10,5,15,3,7,13,18,1,null,6], L = 6, R = 10
输出:23
提示:
树中的结点数量最多为 10000 个。
最终的答案保证小于 2^31。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/range-sum-of-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
// 递归
int ans = 0;
public int rangeSumBST(TreeNode root, int L, int R) {
if(root == null) return ans;
sumBST(root,L,R);
return ans;
}
public void sumBST(TreeNode root, int L, int R){
if(root == null) return;
if(root.val >= L && root.val <= R){
ans += root.val;
}
if(root.val > L){
sumBST(root.left,L,R);
}
if(root.val < R){
sumBST(root.right,L,R);
}
}
// 迭代
public int rangeSumBST2(TreeNode root, int L, int R) {
int ans = 0;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
// 栈的递归如果出问题一定是在while这里!!
while(!stack.isEmpty()){
TreeNode node = stack.pop();
if(node != null){
if(node.val >= L && node.val <= R){
ans += node.val;
}
if(node.val > L){
stack.push(node.left);
}
if(node.val < R){
stack.push(node.right);
}
}
}
return ans;
}
给定一个树,按中序遍历重新排列树,使树中最左边的结点现在是树的根,并且每个结点没有左子结点,只有一个右子结点。
示例 :
输入:[5,3,6,2,4,null,8,1,null,null,null,7,9]
5
/ \
3 6
/ \
2 4 8
/ / \
1 7 9
输出:[1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]
1
2
3
4
5
6
7
8
9
提示:
给定树中的结点数介于 1 和 100 之间。
每个结点都有一个从 0 到 1000 范围内的唯一整数值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/increasing-order-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public TreeNode increasingBST(TreeNode root) {
List<Integer> list = new ArrayList<>();
getList(root,list);
TreeNode tree = new TreeNode(0);
tree.left = null;
TreeNode p = tree;
// 主要是这段代码,构造TreeNode树
// 注意树的构造,左节点没有也需要人为的构造null
for (int x : list) {
TreeNode node = new TreeNode(x);
node.left = null;
p.right = node;
p = p.right;
p.val = node.val;
}
return tree.right;
}
public void getList(TreeNode root, List<Integer> list){
if(root == null) return;
getList(root.left,list);
list.add(root.val);
getList(root.right,list);
}
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true;否则返回 false。
示例 1:
输入:[1,1,1,1,1,null,1]
输出:true
示例 2:
输入:[2,2,2,5,2]
输出:false
提示:
给定树的节点数范围是 [1, 100]。
每个节点的值都是整数,范围为 [0, 99] 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/univalued-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public boolean isUnivalTree(TreeNode root) {
if(root == null) return true;
int num = root.val;
return helper(root,num);
}
public boolean helper(TreeNode root, int num){
if(root == null) return true;
if(root.val != num){
return false;
}
return helper(root.left,num) && helper(root.right,num);
}
给出一棵二叉树,其上每个结点的值都是 0 或 1 。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。例如,如果路径为 0 -> 1 -> 1 -> 0 -> 1,那么它表示二进制数 01101,也就是 13 。
对树上的每一片叶子,我们都要找出从根到该叶子的路径所表示的数字。
以 10^9 + 7 为模,返回这些数字之和。
示例:
输入:[1,0,1,0,1,0,1]
输出:22
解释:(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
提示:
树中的结点数介于 1 和 1000 之间。
node.val 为 0 或 1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-root-to-leaf-binary-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
int res = 0;
public int sumRootToLeaf(TreeNode root) {
if(root == null) return 0;
helper(root,0);
return res;
}
public void helper(TreeNode root, int num){
if(root == null) return;
num += root.val;
if(root.left == null && root.right == null){
res += num;
}
// 左和右
helper(root.left, num << 1);
helper(root.right, num << 1);
}