BM10 两个链表的第一个公共结点
题目
思路
- 求两个链表的长度
- 快指针走Math.abs(len1-len2)步
- 快慢指针一起走,直到相遇即可返回
代码
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
// 1. 先统计两个链表长度
if (pHead1 == null || pHead2 == null) {
return null;
}
ListNode cur1 = pHead1;
int len1 = 0;
while (cur1 != null) {
cur1 = cur1.next;
len1++;
}
ListNode cur2 = pHead2;
int len2 = 0;
while (cur2 != null) {
cur2 = cur2.next;
len2++;
}
// 快指针走差距步
int len = Math.abs(len1 - len2);
ListNode longNode = pHead1;
ListNode shortNode = pHead2;
if (len2 > len1) {
longNode = pHead2;
shortNode = pHead1;
}
while (len > 0) {
longNode = longNode.next;
len--;
}
// 一起走
while (longNode != shortNode) {
longNode = longNode.next;
shortNode = shortNode.next;
}
return longNode;
}
BM11 链表相加(二)
题目
思路
- 先逆序两个链表
- 然后逐个相加,注意进位
- 将相加结果逆序
代码
public ListNode ReverseList2 (ListNode head) {
if(head == null || head.next == null) {
return head;
}
ListNode cur = head;
ListNode pre = null;
while (cur != null) {
ListNode curNext = cur.next;
cur.next = pre;
pre = cur;
cur = curNext;
}
return pre;
}
public ListNode addInList (ListNode head1, ListNode head2) {
if(head1 == null) return head2;
if(head2 == null) return head1;
// 1. 逆序两个链表
head1 = ReverseList2(head1);
head2 = ReverseList2(head2);
int next = 0; // 负责进位的
ListNode newHead = null;
ListNode tail = null;
while (head1 != null && head2 != null) {
int val = head1.val + head2.val + next;
if(val > 9) {
next = 1;
val %= 10;
} else {
next = 0;
}
if(newHead == null) {
newHead = tail = new ListNode(val);
} else {
tail.next = new ListNode(val);
tail = tail.next;
}
head1 = head1.next;
head2 = head2.next;
}
while (head2 != null) {
int val = head2.val + next;
if(val > 9) {
next = 1;
val %= 10;
} else {
next = 0;
}
tail.next = new ListNode(val);
tail = tail.next;
head2 = head2.next;
}
while (head1 != null) {
int val = head1.val + next;
if(val > 9) {
next = 1;
val %= 10;
} else {
next = 0;
}
tail.next = new ListNode(val);
tail = tail.next;
head1 = head1.next;
}
if(next == 1) {
tail.next = new ListNode(1);
tail = tail.next;
}
tail.next = null;
return newHead;
}
BM12 单链表的排序
题目
思路
归并排序:先拆解【快慢指针找中间节点,然后拆成两半】,再合并【之前文章写过合并两个有序链表】
注意代码中注释的部分
代码
public ListNode Merge (ListNode pHead1, ListNode pHead2) {
ListNode dummyNode = new ListNode(-1);
ListNode head = dummyNode;
while (pHead1 != null && pHead2 != null) {
if(pHead1.val > pHead2.val) {
head.next = pHead2;
pHead2 = pHead2.next;
} else {
head.next = pHead1;
pHead1 = pHead1.next;
}
head = head.next;
}
head.next = pHead1 == null ? pHead2 : pHead1;
return dummyNode.next;
}
public ListNode sortInList (ListNode head) {
if(head == null || head.next == null) return head;
// 下面代码不行:如果是偶数个,找的是靠后面的节点,会造成死递归
// ListNode slow = head;
// ListNode fast = head;
// while (fast != null && fast.next != null) {
// fast = fast.next.next;
// slow = slow.next;
// }
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
// slow 为中间节点
// tmp 存储后半部分的头节点
ListNode tmp = slow.next;
slow.next = null;
ListNode left = sortInList(head);
ListNode right = sortInList(tmp);
return Merge(left,right);
}
BM13 判断一个链表是否为回文结构
题目
思路
- 逆序链表,然后判断两个链表是否各个节点都相同
- 找中间节点,然后逆序后半部分链表,最后头尾一起走,一直走到 null,则为相同,否则不同
代码
private ListNode getMidNode(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
private ListNode reverse(ListNode mid) {
if (mid == null || mid.next == null) {
return mid;
}
ListNode newHead = reverse(mid.next);
mid.next.next = mid;
mid.next = null;
return newHead;
}
public boolean isPail (ListNode head) {
// 1. 先找中间节点
ListNode mid = getMidNode(head);
// 2. 逆序后半部分链表
ListNode newHead = reverse(mid);
// 3. 遍历判断
while (newHead != null) {
if(newHead.val != head.val) return false;
newHead = newHead.next;
head = head.next;
}
return true;
}
BM14 链表的奇偶重排
题目
思路
相当于分离出奇偶两个链表,然后进行连接即可
代码
public ListNode oddEvenList (ListNode head) {
if(head == null || head.next == null || head.next.next == null) return head;
// 奇数
ListNode odd = head;
// 偶数
ListNode even = head.next;
// 记录下偶数链表的头结点
ListNode tmp = even;
while (even != null && even.next != null) {
odd.next = even.next;
odd = odd.next;
even.next = odd.next;
even = even.next;
}
odd.next = tmp;
return head;
}
BM15 删除有序链表中重复的元素-I
题目
思路
直接遍历链表删除即可,发现当前元素与下一个元素相等就走两步,不然就走一步
代码
public ListNode deleteDuplicates (ListNode head) {
if(head == null || head.next == null) return head;
ListNode cur = head;
while (cur.next != null) {
if(cur.val == cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
}
BM16 删除有序链表中重复的元素-II
题目
思路
需要一个虚拟头结点,pre指向虚拟头结点,然后cur用来遍历是否有重复元素,有重复元素就全部跳过,直到发现没有重复的 pre.next = cur;若进入循环发现cur 与 cur.next 不重复,则 pre 与 cur 一起往后走
代码
public ListNode deleteDuplicates (ListNode head) {
if(head == null || head.next == null) return head;
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
ListNode cur = head;
while (cur != null && cur.next != null) {
if(cur.val == cur.next.val) {
int tmp = cur.val;
while (cur != null && cur.val == tmp) {
cur = cur.next;
}
pre.next = cur;
} else {
pre = pre.next;
cur = cur.next;
}
}
return dummyNode.next;
}