Keep Calm and Carry On

1. Morris Traversal 二叉树遍历

Morris Traversal 可以实现不用栈、非递归地遍历二叉树,使用O(1)的空间复杂度遍历一颗二叉树,保证时间复杂度也是O(N)。
二叉搜索树中的众数

  1. Morris 中序遍历
  • 如果当前节点没有左子树,则输出当前节点,然后跳转到当前节点的右子树上;
  • 如果当前节点有左子树,那么当前节点的前驱节点一定在左子树的上,只要在左子树一直往右走就可以找到;
    • 如果前驱节点没有右子树,那么将前驱节点的 right 指针指向当前节点(这是为了遍历完前驱节点之后可以找到当前节点)
    • 如果前驱节点的右子树是当前节点,那么说明前驱节点已经被遍历过,而且被修改了 right 指针,这时可以将前驱节点的 right 指针置为 nullptr,然后遍历当前节点,跳转到当前节点的右子树
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void morris_inorder_traversal(TreeNode *root) {
while ( cur ) {
if ( !cur->left ) {
// 当前节点没有左子树,遍历当前节点,跳转到右子树
std::cout << cur->val << ' ';
cur = cur->right;
}
else {
// 当前节点有左子树,先找到前驱
pre = cur->left;
while ( pre->right && pre->right != cur ) pre = pre->right;
if ( !pre->right ) {
pre->right = cur;
cur = cur->left;
}
else {
pre->right = nullptr;
std::cout << cur->val << ' ';
cur = cur->right;
}
}
}
}

2. Y型链表找公共相交节点

两个链表的第一个公共节点
描述:一个Y型链表找到相交的节点,简单来说有三种方法:

  1. 最简单的方法:使用一个存储链表1,然后遍历链表2,检查是否有节点在链表1出现,空间复杂度O(N);
  2. 另外两个方法如下图:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Solution1
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
// O(N)的空间复杂度当然简单,直接使用一个哈希表存储其中一个链表即可
int count1 = 0, count2 = 0;
ListNode *cur1 = headA, *cur2 = headB;
while ( cur1 ) {
++count1;
cur1 = cur1->next;
}
while ( cur2 ) {
++count2;
cur2 = cur2->next;
}
if ( count1 > count2 ) {
cur1 = headA;
cur2 = headB;
} else {
cur1 = headB;
cur2 = headA;
}
int difference = count1 > count2 ? count1 - count2 : count2 - count1;
while ( difference ) {
cur1 = cur1->next;
--difference;
}
while ( cur1 && cur2 ) {
if ( cur1 == cur2 ) return cur1;
cur1 = cur1->next;
cur2 = cur2->next;
}
return nullptr;
}
};

// Solution2
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *cur1 = headA, *cur2 = headB;
while ( cur1 != cur2 ) {
cur1 = cur1 ? cur1->next : headB;
cur2 = cur2 ? cur2->next : headA;
}
return cur1;
}
};