链表七怪
1.合并两个有序链表
(1) 题目描述
01 | #21 | LeetCode链接-合并两个有序链表 |
---|
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
(2) 题解代码
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode();
ListNode p1 = list1;
ListNode p2 = list2;
ListNode p = dummy;
while(p1 != null && p2 != null){
if(p1.val <= p2.val){
p.next = p1;
p1 = p1.next;
}else{
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if (p1 != null) {
p.next = p1;
} else {
p.next = p2;
}
return dummy.next;
}
}
2.链表的分解
(1) 题目描述
06 | #86 | LeetCode链接-分隔链表 |
---|
给你一个链表的头节点 head
和一个特定值 x
,请你对链表进行分隔,使得所有 小于 x
的节点都出现在 大于或等于 x
的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
(2) 题解代码
第一版,麻麻赖赖版
class Solution {
void insertAtTail(ListNode head, ListNode newNode) {
ListNode cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = newNode;
}
public ListNode partition(ListNode head, int x) {
ListNode bigger = new ListNode(0);
ListNode smaller = new ListNode(0);
ListNode cur = head;
while(cur != null){
if(cur.val < x){
insertAtTail(smaller,new ListNode(cur.val));
}
if(cur.val >= x){
insertAtTail(bigger,new ListNode(cur.val));
}
cur = cur.next;
}
ListNode result = new ListNode(0);
insertAtTail(result,smaller.next);
insertAtTail(result,bigger.next);
return result.next;
}
}
第二版,XXXXX
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode cur = head;
List<Integer> big = new ArrayList<>();
List<Integer> small = new ArrayList<>();
List<Integer> result = new ArrayList<>();
while(cur != null){
if(cur.val < x) small.add(cur.val);
if(cur.val >= x) big.add(cur.val);
cur = cur.next;
}
result.addAll(small);
result.addAll(big);
cur = head;
int index = 0;
while(cur != null){
cur.val = result.get(index);
index++;
cur = cur.next;
}
return head;
}
}
第三版
public ListNode partition(ListNode head, int x) {
ListNode smallHead = new ListNode(0);
ListNode smallTail = smallHead;
ListNode largeHead = new ListNode(0);
ListNode largeTail = largeHead;
while (head != null) {
if (head.val < x) {
smallTail.next = head;
smallTail = smallTail.next;
} else {
largeTail.next = head;
largeTail = largeTail.next;
}
head = head.next;
}
largeTail.next = null; // Set the next of largeTail to null to avoid cycles
smallTail.next = largeHead.next; // Connect the small list to the large list
return smallHead.next;
}
3.合并 k
个有序链表
(1) 题目描述
03 | #23 | LeetCode链接-合并 K 个升序链表 |
---|
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
(2) 题解代码
class Solution {
ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode();
ListNode p1 = list1;
ListNode p2 = list2;
ListNode p = dummy;
while(p1 != null && p2 != null){
if(p1.val <= p2.val){
p.next = p1;
p1 = p1.next;
}else{
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if (p1 != null) {
p.next = p1;
} else {
p.next = p2;
}
return dummy.next;
}
public ListNode mergeKLists(ListNode[] lists) {
ListNode result = null;
for (ListNode list: lists) {
result = mergeTwoLists(result, list);
}
return result;
}
}
4.链表的倒数第 k
个节点
(1) 题目描述
04 | #剑指 Offer 22 | LeetCode链接-链表中倒数第k个节点 |
---|
寻找单链表的倒数第 k
个节点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
(2) 题解代码
第一版,麻麻烦烦版
class Solution {
ListNode deleteLastNode(ListNode head) {
if (head == null || head.next == null) {
return null; // 链表为空或只有一个节点的情况
}
ListNode sentinel = new ListNode(0); // 哨兵节点
sentinel.next = head;
ListNode prev = sentinel;
ListNode curr = head;
while (curr.next != null) {
prev = curr;
curr = curr.next;
}
prev.next = null; // 删除最后一个节点
return sentinel.next;
}
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(100);
ListNode dummyTail = new ListNode(-100);
ListNode slow = new ListNode(0);
int slowCount = 0;
ListNode fast = new ListNode(0);
int fastCount = 0;
dummyHead.next = head;
slow = dummyHead;
fast = dummyHead;
while(fast != null){
fastCount++;
if(fast.next != null){
fast = fast.next;
}else{
fast.next = dummyTail;
break;
}
}
while(slow != null && slowCount < fastCount-n-1){
slowCount++;
slow = slow.next;
}
slow.next = slow.next.next;
deleteLastNode(dummyHead);
return dummyHead.next;
}
}
第二版
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode turtle = dummy;
ListNode rabbit = dummy;
for(int i=0 ; i<=n ; i++){
rabbit = rabbit.next;
}
while(rabbit != null){
turtle = turtle.next;
rabbit = rabbit.next;
}
if(turtle.next == rabbit){
turtle.next = rabbit;
}else{
turtle.next = turtle.next.next;;
}
return dummy.next;
}
}
5.链表的中点
(1) 题目描述
05 | #NULL | LeetCode链接-链表的中间结点 |
---|
寻找单链表的中点
找到链表的中点,如果链表有偶数个结点,返回第二个中点。
(2) 题解代码
public class Solution {
public ListNode middleNode(ListNode head) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
while(fast != null){
slow = slow.next;
fast = fast.next;
if(fast != null){
fast = fast.next;
}
}
return slow;
}
}
6.环形链表
(1) 题目描述
06 | #141 | LeetCode链接-环形链表 |
---|---|---|
#142 | LeetCode链接-环形链表 II |
判断单链表是否包含环并找出环起点
给你一个链表的头节点 head
,判断链表中是否有环。
(2) 题解代码
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head == null) return null;
ListNode dummy = new ListNode();
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
boolean isCycle = false;
while(fast != null){
slow = slow.next;
fast = fast.next;
if(fast != null){
fast = fast.next;
}
if(fast == slow){
isCycle = true;
break;
}
}
if(isCycle){
fast = dummy;
while(fast != slow){
fast = fast.next;
slow = slow.next;
if(fast == slow) return slow;
}
}
return null;
}
}
7.相交链表
(1) 题目描述
03 | #160 | LeetCode链接-相交链表 |
---|
判断两个单链表是否相交并找出交点
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。
如果两个链表不存在相交节点,返回 null
。
(2) 题解代码
第一版
- 设置虚拟结点,避免处理链表只存在一个结点的情况
- 设置乌龟组和兔子组,绿色乌龟和绿色兔子先跑,
- 谁先跑到头再让这一组的红色龟兔开始跑,
- 直到龟兔相遇
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode dummyA = new ListNode();
dummyA.next = headA;
ListNode dummyB = new ListNode();
dummyB.next = headB;
ListNode greenRabbit = dummyA;
ListNode redRabbit = dummyA;
ListNode greenTurtle = dummyB;
ListNode redTurtle = dummyB;
while(greenRabbit != null && greenTurtle != null){
greenRabbit = greenRabbit.next;
greenTurtle = greenTurtle.next;
}
if(greenRabbit == null){
while(greenTurtle != null){
greenTurtle = greenTurtle.next;
redTurtle = redTurtle.next;
}
}
if(greenTurtle == null){
while(greenRabbit != null){
greenRabbit = greenRabbit.next;
redRabbit = redRabbit.next;
}
}
while(redRabbit != null && redTurtle != null){
redRabbit = redRabbit.next;
redTurtle = redTurtle.next;
if(redRabbit == redTurtle){
return redRabbit;
}
}
return headA;
}
}
第二版
- 只有一只兔子和一只乌龟
- 这种情况,返回头结点时需要换链
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode dummyA = new ListNode();
dummyA.next = headA;
ListNode dummyB = new ListNode();
dummyB.next = headB;
ListNode rabbit = dummyA;
ListNode turtle = dummyB;
while(rabbit != null && turtle != null){
rabbit = rabbit.next;
turtle = turtle.next;
}
if(rabbit == null){
rabbit = dummyB;
while(turtle != null){
rabbit = rabbit.next;
turtle = turtle.next;
}
turtle = dummyA;
}
if(turtle == null){
turtle = dummyA;
while(rabbit != null){
rabbit = rabbit.next;
turtle = turtle.next;
}
rabbit = dummyB;
}
while(rabbit != null && turtle != null){
rabbit = rabbit.next;
turtle = turtle.next;
if(rabbit == turtle){
return rabbit;
}
}
return headA;
}
}
第三版
- 简洁又优雅
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode rabbit = headA, turtle = headB;
while (rabbit != turtle) {
rabbit = rabbit == null ? headB : rabbit.next;
turtle = turtle == null ? headA : turtle.next;
}
return rabbit;
}
}