「每日LeetCode」2020年9月19日

本文最后更新于:2023年3月19日 晚上

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先、剑指 Offer 52. 两个链表的第一个公共节点、剑指 Offer 55 - II. 平衡二叉树、剑指 Offer 28. 对称的二叉树

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

1
2
3
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6

示例 2:

1
2
3
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉搜索树中。

注意:本题与主站 235 题相同:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

思路

结合二叉搜索树的特点,当当前节点值都比 p、q 要大的时候,说明公共节点在左边,返回左子树,都要小的时候说明公共节点在右边,返回右子树。当值在两个之间时,就为公共祖先。
吐槽一下力扣,这题不能使用 js 写,ts 返回结构限制为 TreeNode,期望得到的答案却是 number :)。所以贴一下主站 235 的答案。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/

/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function (root, p, q) {
if (!root) return null;
if (root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left, p, q);
if (root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
return root;
};

剑指 Offer 52. 两个链表的第一个公共节点

输入两个链表,找出它们的第一个公共节点。
如下面的两个链表

在节点 c1 开始相交。

示例 1:

1
2
3
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例  2:

1
2
3
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例  3:

1
2
3
4
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null

注意:

思路

暴力双重循环

很容易可以得到一种解法,双重遍历比较 a、b 每个节点的 next 是否相等,相等即可直接返回

哈希表

若没有限制空间复杂度为 O(1),可以使用 hash 表进行判断,则满足 O(n)的时间复杂度要求

双指针法

设交集链表长 c,链表 1 除交集的长度为 a,链表 2 除交集的长度为 b,有

  • a + c + b = b + c + a
  • 若无交集,则 a + b = b + a

所以当 tmpA 或 tmpB 为空时,将他们设置为另一条链的头结点,再走不是交集的那个长度,最后一定会在交点处遇上

解答

暴力双重循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/

/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
let tmpA = headA;
let tmpB = headB;
while (tmpA && tmpB) {
let tmp = tmpB;
while (tmp) {
if (tmpA === tmp) return tmpA;
tmp = tmp.next;
}
tmpA = tmpA.next;
}
return null;
};

哈希表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/

/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
let map = new Map();
while (headA) {
map.set(headA, true);
headA = headA.next;
}
while (headB) {
if (map.get(headB)) return headB;
headB = headB.next;
}
return null;
};

双指针法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/

/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
let tmpA = headA,
tmpB = headB;
while (tmpA != tmpB) {
tmpA = tmpA ? tmpA.next : headA;
tmpB = tmpB ? tmpB.next : headB;
}
return tmpA;
};

剑指 Offer 55 - II. 平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过 1,那么它就是一棵平衡二叉树。
 示例 1:

1
2
3
4
5
6
7
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true

示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]

1
2
3
4
5
6
7
8
				1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false

限制:

  • 1 <= 树的结点个数 <= 10000

注意:本题与主站 110  题相同:https://leetcode-cn.com/problems/balanced-binary-tree/

思路

本题结合了求树的最大深度,对每一个节点返回其左右子树的最大深度,判断他们的绝对值是否大于 1,大于即返回 false。再递归计算树里的每一个节点是否都符合这个规则即可。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isBalanced = function (root) {
if (!root) return true;
return (
Math.abs(getDeep(root.left) - getDeep(root.right)) <= 1 &&
isBalanced(root.left) &&
isBalanced(root.right)
);
};

const getDeep = (root) => {
if (!root) return 0;
return Math.max(1 + getDeep(root.left), 1 + getDeep(root.right));
};

剑指 Offer 28. 对称的二叉树

难度简单 83 收藏分享切换为英文关注反馈
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树  [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
 示例 1:

1
2
输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

1
2
输入:root = [1,2,2,null,3,null,3]
输出:false

限制:
0 <= 节点个数 <= 1000
注意:本题与主站 101 题相同:https://leetcode-cn.com/problems/symmetric-tree/

思路

写一个判断是否相等的函数。传入树 1 和树 2,如果两个都为空则返回 true 结束递归,如果有一个为空或者两个节点的值不相等则不满足情况返回 false。传入两个节点的值应该相等,同时他们的左右节点应该互相相等才符合对称。不断递归计算即可。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function (root) {
return isSame(root, root);
};

const isSame = (tree1, tree2) => {
if (!tree1 && !tree2) return true;
if ((!tree1 && tree2) || (tree1 && !tree2)) return false;
if (tree1.val === tree2.val)
return isSame(tree1.left, tree2.right) && isSame(tree1.right, tree2.left);
return false;
};

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!