14 Jul 2024
Given an integer array nums where the elements are sorted in ascending order, convert it to a height-balanced binary search tree.
A height-balanced binary tree is a binary tree in which the depth of the two subtrees of every node never differs by more than one.
Example 1:

Input: nums = [-10,-3,0,5,9] Output: [0,-3,9,-10,null,5] Explanation: [0,-10,5,null,-3,null,9] is also accepted:
Example 2:

Input: nums = [1,3] Output: [3,1] Explanation: [1,null,3] and [3,1] are both height-balanced BSTs.
Constraints:
1 <= nums.length <= 104-104 <= nums[i] <= 104nums is sorted in a strictly increasing order.有序数组,组成高度平衡的二叉搜索树。重点就在于找到中间值,然后左右区间分别构造二叉树的左右子树。
递归解法
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]: len_nums = len(nums) if len_nums < 1: return None elif len_nums == 1: return TreeNode(nums[0]) root_i = len_nums // 2 root = TreeNode(nums[root_i]) root.left = self.sortedArrayToBST(nums[:root_i]) root.right = self.sortedArrayToBST(nums[root_i+1:]) return root
14 Jul 2024
Given the root of a binary tree, return *the length of the diameter of the tree*.
The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.
The length of a path between two nodes is represented by the number of edges between them.
Example 1:

Input: root = [1,2,3,4,5] Output: 3 Explanation: 3 is the length of the path [4,2,1,3] or [5,2,1,3].
Example 2:
Input: root = [1,2] Output: 1
Constraints:
[1, 104].-100 <= Node.val <= 100核心思路:
递归实现(返回节点高度,同时计算递归过程中各个节点的最长直径;这两者都是后序遍历,所以可以循只遍历一次):
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int: self.max_diameter = 0 self.getHeight(root) return self.max_diameter def getHeight(self, node: Optional[TreeNode]) -> int: # 终止条件 if node is None: return 0 # 后序遍历 left_h = self.getHeight(node.left) right_h = self.getHeight(node.right) self.max_diameter = max(left_h + right_h, self.max_diameter) return 1 + max(left_h, right_h)
14 Jul 2024
Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).
Example 1:

Input: root = [1,2,2,3,4,4,3] Output: true
Example 2:

Input: root = [1,2,2,null,3,null,3] Output: false
Constraints:
[1, 1000].-100 <= Node.val <= 100Follow up: Could you solve it both recursively and iteratively?
核心思路:将根节点的左右子树递归对称对比,单个节点的对比包含以下规则:
递归实现:
两个节点的
val对比属于终止条件,并不是中节点的比较,因为节点的比较,除了val之外,还有left和right的对比。单层核心逻辑,
左右中是后序遍历。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isSymmetric(self, root: Optional[TreeNode]) -> bool: if root is None: return True return self.isSame(root.left, root.right) def isSame(self, node_01: Optional[TreeNode], node_02: Optional[TreeNode]) -> bool: # 终止条件 if not node_01 and not node_02: return True if not node_01 or not node_02: return False if node_01.val != node_02.val: return False # 后序处理,左右中(中隐藏在return的逻辑里面了) # 注意,中是指中节点,当前节点的val对比并不是中节点完整的逻辑对比,所以不算中 if not self.isSame(node_01.left, node_02.right): return False if not self.isSame(node_01.right, node_02.left): return False return True
14 Jul 2024
Given the root of a binary tree, invert the tree, and return its root.
Example 1:

Input: root = [4,2,7,1,3,6,9] Output: [4,7,2,9,6,3,1]
Example 2:

Input: root = [2,1,3] Output: [2,3,1]
Example 3:
Input: root = [] Output: []
Constraints:
[0, 100].-100 <= Node.val <= 100核心思想:使用前序或后序遍历来处理。
中序遍历不行的原因是,在左和右子树分别处理完之前,就把中的逻辑(交换左右子树)处理了,相当于左右子树发生了改变,逻辑会比较绕。
递归实现:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: self.invertNode(root) return root def invertNode(self, node: Optional[TreeNode]): if node is None: return # 前序遍历 # 处理`中`,交换左右子树 node.left, node.right = node.right, node.left # 递归处理左子树 self.invertNode(node.left) # 递归处理右子树 self.invertNode(node.right)
14 Jul 2024
Given the root of a binary tree, return its maximum depth.
A binary tree’s maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Example 1:

Input: root = [3,9,20,null,null,15,7] Output: 3
Example 2:
Input: root = [1,null,2] Output: 2
Constraints:
[0, 104].-100 <= Node.val <= 100核心思想:求最大深度,其实就是求root的高度。求高度使用的是后序遍历,左右中
左右中,最后处理中,才能递归把左和右的结果,拿来给中用。为什么不使用前序遍历,中左右,来直接求深度呢?因为无法让下层节点利用上层节点来递归
递归实现:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def maxDepth(self, root: Optional[TreeNode]) -> int: return self.getHeight(root) def getHeight(self, node: Optional[TreeNode]) -> int: # 终止条件 if node is None: return 0 # 单层核心逻辑 # 以下四条语句,可以合并为最后一条语句 # left_height = self.getHeight(node.left) # right_height = self.getHeight(node.right) # cur_height = max(left_height, right_height) + 1 # return cur_height return 1 + max(self.getHeight(node.left), self.getHeight(node.right))
06 Jul 2024
Given the root of a binary tree, return the inorder traversal of its nodes’ values.
Example 1:

Input: root = [1,null,2,3] Output: [1,3,2]
Example 2:
Input: root = [] Output: []
Example 3:
Input: root = [1] Output: [1]
Constraints:
[0, 100].-100 <= Node.val <= 100Follow up: Recursive solution is trivial, could you do it iteratively?
中序遍历,就是左中右这种顺序
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: res = [] self.traversal(root, res) return res def traversal(self, node: Optional[TreeNode], res: List[int]): if node is None: return self.traversal(node.left, res) res.append(node.val) self.traversal(node.right, res)
中序遍历,就是左中右顺序。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: answer: List[int] = [] st_node: List[int] = [] cur_node = root # 中序遍历:左中右 # 左子树依序入栈,到底后逐个弹出,处理中和右 while cur_node or st_node: # 先处理当前节点的左子树 while cur_node: st_node.append(cur_node) cur_node = cur_node.left # 将栈顶元素弹出栈(左节点首先会在栈顶) cur_node = st_node.pop() answer.append(cur_node.val) # 若无right,cur_node为None,会在下个循环中重新pop一个 cur_node = cur_node.right return answer
06 Jul 2024
在电脑科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构[1]。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。
二叉树的第i层至多拥有2i−1个节点;深度为k的二叉树至多总共有2k+1−1个节点(定义根节点所在深度 k0=0!),而总计拥有节点数符合的,称为“满二叉树”;深度为k有n个节点的二叉树,当且仅当其中的每一节点,都可以和深度k的满二叉树,序号1到n的节点一对一对应时,称为完全二叉树。对任何一棵非空的二叉树T,如果其叶片(终端节点)数为n0,分支度为2的节点数为n2,则n0=n2+1。
根据结构和性质的不同,二叉树可以分为许多种类。以下是一些常见的二叉树种类及其特点:
总结 二叉树还有很多其他种类,每种都有其特定的用途和性质。根据具体应用场景选择合适的二叉树可以提高算法的效率和性能。
综上所述,二叉树作为一种基础的数据结构,在计算机科学的发展中起到了重要的作用。从最初的数学概念到如今各种复杂的变体和应用,二叉树一直是计算机科学研究和应用的核心部分。
二叉树在内存中,使用链式存储。
也有线性存储,即使用数组来存储。
假设我们在一个32位系统上,int 和指针都占用4个字节(32位)。我们将val设置为42,并假设left和right指针为空(即NULL)。
在二进制位模式下:
42 的二进制表示是 00000000 00000000 00000000 00101010。NULL 的二进制表示是 00000000 00000000 00000000 00000000。因此,内存布局将是:
地址: 0x1000 0x1004 0x1008 0x100C
+--------+--------+--------+--------+
值: | 42 | NULL | NULL |
+--------+--------+--------+--------+
字段: | val | left | right |
+--------+--------+--------+--------+
64位系统中,val值不够长度会进行补齐,保持长度和后面的指针一致。
05 Jul 2024
You are given the heads of two sorted linked lists list1 and list2.
Merge the two lists into one sorted list. The list should be made by splicing together the nodes of the first two lists.
Return the head of the merged linked list.
Example 1:

Input: list1 = [1,2,4], list2 = [1,3,4] Output: [1,1,2,3,4,4]
Example 2:
Input: list1 = [], list2 = [] Output: []
Example 3:
Input: list1 = [], list2 = [0] Output: [0]
Constraints:
[0, 50].-100 <= Node.val <= 100list1 and list2 are sorted in non-decreasing order.# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: pre = ListNode() tail = pre while list1 is not None and list2 is not None: if list1.val > list2.val: tail.next = list2 list2 = list2.next else: tail.next = list1 list1 = list1.next tail = tail.next tail.next = list1 if list1 is not None else list2 return pre.next
- 使用一个pre节点,避免了处理第一个节点的特殊情况
- while循环只处理两个链表都没到尾部的情况,其他一个到尾部时单独处理,这样避免了重复判断None的语句。
04 Jul 2024
Given the head of a singly linked list, reverse the list, and return the reversed list.
Example 1:

Input: head = [1,2,3,4,5] Output: [5,4,3,2,1]
Example 2:

Input: head = [1,2] Output: [2,1]
Example 3:
Input: head = [] Output: []
Constraints:
[0, 5000].-5000 <= Node.val <= 5000Follow up: A linked list can be reversed either iteratively or recursively. Could you implement both?
第一个元素指向None,然后后续元素逐个指向前一个元素,完毕
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: pre = None cur = head while cur: next_node = cur.next cur.next = pre pre, cur = cur, next_node return pre
其实还是双指针,只是换了递归的写法
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: return self.reverse(None, head) def reverse(self, pre: Optional[ListNode], cur: Optional[ListNode]) -> Optional[ListNode]: if cur == None: return pre temp = cur.next cur.next = pre return self.reverse(cur, temp)
04 Jul 2024
Given head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail’s next pointer is connected to. Note that pos is not passed as a parameter.
Return true if there is a cycle in the linked list. Otherwise, return false.
Example 1:

Input: head = [3,2,0,-4], pos = 1 Output: true Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).
Example 2:

Input: head = [1,2], pos = 0 Output: true Explanation: There is a cycle in the linked list, where the tail connects to the 0th node.
Example 3:

Input: head = [1], pos = -1 Output: false Explanation: There is no cycle in the linked list.
Constraints:
[0, 104].-105 <= Node.val <= 105pos is -1 or a valid index in the linked-list.Follow up: Can you solve it using O(1) (i.e. constant) memory?
使用一个备忘录,记录每个节点,若后面有重复,即节点存入前,节点已经存在。那么就有环形存在
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def hasCycle(self, head: Optional[ListNode]) -> bool: temp: List[ListNode] = [] while head is not None: if head in temp: return True temp.append(head) head = head.next return False
基于朴素解法,只是数据结构换成了dict
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def hasCycle(self, head: Optional[ListNode]) -> bool: temp: Dict[ListNode, int] = {} while head is not None: if head in temp: return True temp[head] = 0 head = head.next return False