链表中倒数第k个结点
题目
输入一个链表,输出该链表中倒数第k个结点。
Example
解题
- 先求链表长度,然后头节点走 len - k 步(需要遍历两遍) - 注意len 要小于k才有结果的
- 快慢指针,快指针先走 k 步,然后快慢指针一起走(一遍遍历搞定)
代码
public ListNode FindKthToTail(ListNode head, int k) {
if (head == null || k <= 0) {
return null;
}
// fast先走k步
ListNode fast = head;
ListNode slow = head;
while (k > 0) {
// 可能k大于链表长度
if (fast == null) return null;
fast = fast.next;
k--;
}
// fast与slow一起走
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
反转链表
题目
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
Example
解题
- 使用栈结构,先存储,然后重构链表
- 三指针法(也叫头插法)
- 递归
代码
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head == null || head.next == null) {
return head;
}
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode curNext = cur.next;
cur.next = pre;
pre = cur;
cur = curNext;
}
return pre;
}
}0
public ListNode ReverseList(ListNode head) {
if(head == null || head.next == null) {
return head;
}
ListNode newHead = ReverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
合并两个排序的链表
题目
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
Example
解题
- 遍历两个链表(如图所示,相当于重构一个新链表)
- 递归(每一次递归,确定一个值)
代码
public ListNode Merge(ListNode list1, ListNode list2) {
if (list1 == null) {
return list2;
}
if (list2 == null) {
return list1;
}
ListNode head = null;
ListNode tail = null;
if (list1.val > list2.val) {
head = tail = list2;
list2 = list2.next;
} else {
head = tail = list1;
list1 = list1.next;
}
while (list1 != null && list2 != null) {
if (list1.val > list2.val) {
tail.next = list2;
list2 = list2.next;
} else {
tail.next = list1;
list1 = list1.next;
}
tail = tail.next;
}
tail.next = list1 == null ? list2 : list1;
return head;
}
public ListNode Merge(ListNode list1, ListNode list2) {
if (list1 == null) {
return list2;
}
if (list2 == null) {
return list1;
}
ListNode head = null;
if(list1.val > list2.val) {
head = list2;
list2 = list2.next;
} else {
head = list1;
list1 = list1.next;
}
head.next = Merge(list1,list2);
return head;
}
树的子结构
题目
输入两棵二叉树A,B,判断B是不是A的子结构。(我们约定空树不是任意一个树的子结构)
Example
解题
因为可能 B 这棵树只有一个节点,所以我们需要遍历 A 这棵树的每一个节点,就需要深度遍历 / 广度遍历,这里我使用的就是二叉树的前序遍历(从当前根节点开始判断,如果不是,就判断左数;否则,递归右数)
代码
// 比较root1是否包含root2
public boolean isSameChild(TreeNode root1, TreeNode root2) {
if(root2 == null) return true; // root2树递归完了,就说明 root2是roo1的子树了
if(root1 == null) return false;
if (root1.val != root2.val) {
return false;
}
return isSameChild(root1.left, root2.left) &&
isSameChild(root1.right, root2.right);
}
public boolean HasSubtree(TreeNode root1, TreeNode root2) {
if (root1 == null || root2 == null) return false;
// 1. 先找起始位置
boolean result = false;
if (root1.val == root2.val) {
result = isSameChild(root1, root2);
}
if (result != true) {
result = HasSubtree(root1.left, root2);
}
if (result != true) {
result = HasSubtree(root1.right, root2);
}
return result;
}