链表必刷题第一部分
206.反转链表
给你单链表的头节点head,请你反转链表,并返回反转后的链表。
![](https://assets.leetcode.com/uploads/2021/02/19/rev1ex1.jpg)
解题思路一:迭代法
迭代方法的关键在于使用三个指针(prev, curr, next)来遍历链表,依次修改指针的指向。详细步骤如下:
- 初始化三个指针:prev 指向空(null),curr 指向链表头部,next 指向空(null)。
- 遍历链表:
- 在每一次迭代中,首先将 curr 的下一个节点保存到 next。
- 然后修改 curr 的下一个节点指向 prev,实现反转。
- 更新 prev 和 curr 指针,将它们向前移动一个节点。
- 重复这个过程直到 curr 为空。
- 当迭代结束时,prev 指向反转后的链表头部。
解题思路二:递归法
递归方法的关键在于从最后一个节点开始反转,并且在递归过程中修改指针的指向。详细步骤如下:
- 如果当前节点(head)为空或者其下一个节点为空,直接返回当前节点(递归的基本情况)。
- 反转从当前节点的下一个节点开始的子链表,并将返回的新头部赋值给 new_head。
- 修改当前节点的下一个节点的指向为当前节点,即 head.next.next = head。
- 将当前节点的下一个节点设为空,即 head.next = null。
- 返回新的头部节点 new_head。
// 迭代法
ListNode* reverseList(ListNode* head) {
ListNode *cur = head, *pre = nullptr, *next = nullptr;
while(cur != nullptr) {
next = cur-> next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 递归法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode* new_head = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return new_head;
}
};
// 迭代法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
ListNode next = null;
while (curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
// 递归法
public class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode new_head = reverseList(head.next);
head.next.next = head;
head.next = null;
return new_head;
}
}
// 迭代法
func reverseList(head *ListNode) *ListNode {
var prev *ListNode
curr := head
var next *ListNode
for curr != nil {
next = curr.Next
curr.Next = prev
prev = curr
curr = next
}
return prev
}
// 递归法
func reverseList(head *ListNode) *ListNode {
if head==nil||head.Next==nil{
return head
}
last := reverseList(head.Next)
head.Next.Next = head
head.Next = nil
return last
}
83.删除排序链表中的重复元素
给定一个已排序的链表的头head,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。
![](https://assets.leetcode.com/uploads/2021/01/04/list1.jpg)
解题思路一:迭代法
删除排序链表中的重复元素的思路是遍历链表,并比较相邻的节点,如果两个相邻节点的值相同,则删除其中一个。详细步骤如下:
- 初始化一个指针 curr 指向链表头部。
- 遍历链表:
- 比较 curr 节点和 curr 的下一个节点的值:
- 如果值相同,则将 curr 的下一个节点指向下一个的下一个节点(即删除 curr 的下一个节点)。
- 如果值不同,则将 curr 指针向前移动一个节点。
- 重复这个过程直到 curr 或者 curr 的下一个节点为空。
- 比较 curr 节点和 curr 的下一个节点的值:
- 返回链表头部节点。
解题思路二:递归法
递归删除排序链表中的重复元素的思路是将问题分解为两部分:首先处理头节点及其重复元素,然后递归处理剩余链表。这种方法的关键在于利用递归处理子链表,并将结果链接到当前节点。详细步骤如下:
- 递归的基本情况:如果链表为空(head 为 None)或者链表只有一个节点(head.next 为 None),直接返回 head。
- 递归调用:将 head.next 传递给递归函数,将返回的结果赋值给 head.next。
- 比较当前节点(head)和其下一个节点(head.next)的值:
- 如果值相同,说明存在重复元素,此时将当前节点的下一个节点指向下一个的下一个节点(即删除 head 的下一个节点),并保持当前节点不变。
- 如果值不同,说明不存在重复元素,直接返回当前节点。
- 返回链表头部节点。
//迭代法
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* curr = head;
while (curr != nullptr && curr->next != nullptr) {
if (curr->val == curr->next->val) {
curr->next = curr->next->next;
} else {
curr = curr->next;
}
}
return head;
}
};
// 递归法
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
head->next = deleteDuplicates(head->next);
if (head->val == head->next->val) {
head = head->next;
}
return head;
}
};
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
// 迭代法
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode curr = head;
while (curr != null && curr.next != null) {
if (curr.val == curr.next.val) {
curr.next = curr.next.next;
} else {
curr = curr.next;
}
}
return head;
}
}
// 递归法
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) {
return head;
}
head.next = deleteDuplicates(head.next);
if (head.val == head.next.val) {
head = head.next;
}
return head;
}
}
// 迭代法
func deleteDuplicates(head *ListNode) *ListNode {
curr := head
for curr != nil && curr.Next != nil {
if curr.Val == curr.Next.Val {
curr.Next = curr.Next.Next
} else {
curr = curr.Next
}
}
return head
}
// 递归法
func deleteDuplicates(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
head.Next = deleteDuplicates(head.Next)
if head.Val == head.Next.Val {
head = head.Next
}
return head
}
25.K个一组翻转链表
给你链表的头节点head,每k个节点一组进行翻转,请你返回修改后的链表。k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有顺序。
![](https://assets.leetcode.com/uploads/2020/10/03/reverse_ex1.jpg)
解题思路
将链表中的每 k 个节点分为一组,然后对每组进行翻转,可以用迭代和递归两种方式,迭代法的代价较小,更推荐迭代法。
解题思路一:迭代法
代码的主要思路是将链表分为已翻转部分、待翻转部分和未处理部分。我们遍历整个链表,每次取待翻转部分的k个节点进行翻转,然后将翻转后的部分连接到已翻转部分的尾部。若最后一组节点数量不足k个,则不翻转。
- 首先,检查输入的链表是否为空或k是否为1。如果满足这些条件,则不需要翻转链表,直接返回head即可。
- 创建一个虚拟节点(dummy)并将其next指针指向链表的头节点。这个虚拟节点有助于处理边界条件,使代码更简洁。
- 初始化prev、curr和temp三个指针,分别表示已翻转部分的尾节点、待翻转部分的头节点和临时节点。
- 遍历链表,统计链表的长度。
- 使用while循环处理链表。当链表剩余的节点数大于等于k时,进入循环。
- 在循环内,我们需要翻转k个节点。通过一个for循环,迭代k-1次。
- 将临时指针temp指向待翻转部分的第二个节点。
- 更新curr的next指针,使其跳过temp。
- 将temp插入到prev和prev->next之间,完成翻转操作。
- 更新prev的next指针,指向temp。
- 完成一组k个节点的翻转后,更新prev为已翻转部分的新尾节点(即curr)。
- 更新curr指针,使其指向未处理部分的头节点。
- 减少链表的剩余长度(count -= k)。
- 当所有节点都处理完毕时,返回虚拟节点(dummy)的next指针,即翻转后链表的头节点。
解题思路二:递归法
使用递归的方法,并且不需要预先计算链表的长度。详细步骤如下:
- 遍历链表,使用
cur
指针前进 k 步。如果在达到 k 步之前遇到链表末尾(即cur == nil
),说明剩余节点不足 k 个,直接返回head
,保持原有顺序。 - 调用
reverse
函数翻转当前分组,该函数接受两个参数:分组的起始节点head
和分组的结束节点的下一个节点cur
。翻转后的链表头部为newHead
。 - 递归调用
reverseKGroup
函数处理剩余的链表。将翻转后的当前分组的尾节点(即原始head
节点)的Next
指针指向递归调用的结果。 - 返回翻转后的链表头部节点
newHead
。
// 迭代法
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (!head || k == 1) return head;
ListNode dummy(-1);
dummy.next = head;
ListNode *prev = &dummy, *curr = head, *temp;
int count = 0;
while (head) {
count++;
head = head->next;
}
while (count >= k) {
for (int i = 1; i < k; i++) {
temp = curr->next;
curr->next = temp->next;
temp->next = prev->next;
prev->next = temp;
}
prev = curr;
curr = prev->next;
count -= k;
}
return dummy.next;
}
};
// 递归法
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* cur = head;
int count = 0;
while (cur != nullptr && count < k) {
cur = cur->next;
count++;
}
if (count == k) {
ListNode* newHead = reverse(head, cur);
head->next = reverseKGroup(cur, k);
return newHead;
}
return head;
}
ListNode* reverse(ListNode* start, ListNode* end) {
ListNode* prev = nullptr, *curr = start;
while (curr != end) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
// 迭代法
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null || k == 1) return head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode prev = dummy, curr = head, temp;
int count = 0;
while (head != null) {
count++;
head = head.next;
}
while (count >= k) {
for (int i = 1; i < k; i++) {
temp = curr.next;
curr.next = temp.next;
temp.next = prev.next;
prev.next = temp;
}
prev = curr;
curr = prev.next;
count -= k;
}
return dummy.next;
}
}
// 递归法
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode cur = head;
int count = 0;
while (cur != null && count < k) {
cur = cur.next;
count++;
}
if (count == k) {
ListNode newHead = reverse(head, cur);
head.next = reverseKGroup(cur, k);
return newHead;
}
return head;
}
private ListNode reverse(ListNode start, ListNode end) {
ListNode prev = null, curr = start;
while (curr != end) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
// 迭代法
func reverseKGroup(head *ListNode, k int) *ListNode {
if head == nil || k == 1 {
return head
}
dummy := &ListNode{-1, head}
prev, curr := dummy, head
count := 0
for head != nil {
count++
head = head.Next
}
for count >= k {
for i := 1; i < k; i++ {
temp := curr.Next
curr.Next = temp.Next
temp.Next = prev.Next
prev.Next = temp
}
prev = curr
curr = prev.Next
count -= k
}
return dummy.Next
}
// 递归法
func reverseKGroup(head *ListNode, k int) *ListNode {
cur := head
count := 0
for cur != nil && count < k {
cur = cur.Next
count++
}
if count == k {
newHead := reverse(head, cur)
head.Next = reverseKGroup(cur, k)
return newHead
}
return head
}
func reverse(start, end *ListNode) *ListNode {
var prev *ListNode
curr := start
for curr != end {
next := curr.Next
curr.Next = prev
prev = curr
curr = next
}
return prev
}
160.相交链表
给你两个单链表的头节点headA和headB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null。
![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/14/160_statement.png)
解题思路
可以采用双指针的方法。详细步骤如下:
- 初始化两个指针
pA
和pB
,分别指向链表headA
和headB
的头节点。 - 同时遍历两个链表,当指针
pA
和pB
都到达末尾时,它们走过的路径长度相等。如果链表相交,它们会在相交节点相遇;如果链表不相交,它们会在末尾节点null
相遇。- 遍历过程中,如果
pA
到达链表末尾,将其重置为链表headB
的头节点;如果pB
到达链表末尾,将其重置为链表headA
的头节点。 - 这样,当
pA
和pB
再次到达链表末尾时,它们走过的节点数相等,且它们所经过的末尾部分节点完全相同。因此,如果链表相交,它们会在相交节点相遇;如果链表不相交,它们会在末尾节点(null
)相遇。
- 遍历过程中,如果
- 返回相交节点或
null
。
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
//双指针思路
ListNode* a = headA;
ListNode* b = headB;
while(a! = nullptr || b! = nullptr){
if(a == nullptr) a = headB;
if(b == nullptr) b = headA;
if(a == b) return a;
a = a->next;
b = b->next;
}
return nullptr;
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 双指针思路
ListNode a = headA;
ListNode b = headB;
while (a != null || b != null) {
if (a == null) a = headB;
if (b == null) b = headA;
if (a == b) return a;
a = a.next;
b = b.next;
}
return null;
}
}
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
l1, l2 := headA, headB
for l1 != l2{
if l1!=nil{
l1 = l1.Next
}else{
l1 = headB
}
if l2!=nil{
l2 = l2.Next
}else{
l2 = headA
}
}
return l2
}
21.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
![](https://assets.leetcode.com/uploads/2020/10/03/merge_ex1.jpg)
解题思路
可以采用双指针的方法。详细步骤如下:
创建一个虚拟头节点
dummy
,并创建一个指针cur
指向虚拟头节点。cur
将用于构建新的合并后的链表。初始化两个指针
p1
和p2
,分别指向两个升序链表headA
和headB
的头节点。当 p1 和 p2 都不为 null时,执行以下操作:
比较
p1
和p2
节点的值。- 如果
p1.val <= p2.val
,将cur
的next
指针指向p1
,然后将p1
指针前进一步。 - 如果
p1.val > p2.val
,将cur
的next
指针指向p2
,然后将p2
指针前进一步。
- 如果
将
cur
指针前进一步,指向新添加的节点。
当循环结束时,至少有一个链表已经遍历完。将未遍历完的链表(如果有)的剩余部分连接到
cur
的next
指针上。返回虚拟头节点的下一个节点,即为合并后的链表头节点。
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode dummy(-1);
ListNode* cur = &dummy;
ListNode* p1 = list1, *p2 = list2;
while (p1 != nullptr && p2 != nullptr) {
if (p1->val <= p2->val) {
cur->next = p1;
p1 = p1->next;
} else {
cur->next = p2;
p2 = p2->next;
}
cur = cur->next;
}
cur->next = p1 != nullptr ? p1 : p2;
return dummy.next;
}
};
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode cur = dummy;
ListNode p1 = list1, p2 = list2;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
cur.next = p1;
p1 = p1.next;
} else {
cur.next = p2;
p2 = p2.next;
}
cur = cur.next;
}
cur.next = p1 != null ? p1 : p2;
return dummy.next;
}
}
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
dummy := &ListNode{-1, nil}
cur := dummy
p1, p2 := list1, list2
for p1 != nil && p2 != nil {
if p1.Val <= p2.Val {
cur.Next = p1
p1 = p1.Next
} else {
cur.Next = p2
p2 = p2.Next
}
cur = cur.Next
}
if p1 != nil {
cur.Next = p1
} else {
cur.Next = p2
}
return dummy.Next
}
143.重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → L~n - 1~ → Ln 请将其重新排列后变为:
L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
![](https://pic.leetcode-cn.com/1626420311-PkUiGI-image.png)
解题思路
这道题实际是三道题目综合:
- 找到链表的中点:
- 使用快慢指针法,创建两个指针
slow
和fast
,初始时都指向链表头节点head
。 - 同时移动这两个指针,
slow
指针每次移动一步,fast
指针每次移动两步。当fast
指针到达链表尾部时,slow
指针恰好位于链表的中点。
- 使用快慢指针法,创建两个指针
- 反转链表的后半部分:
- 从中点节点
slow
开始,将链表后半部分反转。可以使用迭代或递归方法进行反转。 - 反转后,
slow
指针指向新的子链表头节点。
- 从中点节点
- 合并两个链表:
- 初始化两个指针
p1
和p2
,分别指向原始链表的头节点head
和反转后链表的头节点slow
。 - 依次从两个链表中取出一个节点,将它们按照题目要求的顺序连接起来。
- 不断重复上述过程,直到两个链表中的节点都被连接完毕。
- 初始化两个指针
class Solution {
public:
void reorderList(ListNode* head) {
if(head == nullptr || head->next == nullptr) {
return;
}
// 找到链表中点并将后半部分链表翻转
ListNode *slow = head, *fast = head;
while(fast->next != nullptr && fast->next->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
ListNode *mid = slow->next;
slow->next = nullptr;
mid = reverse(mid);
// 将前半部分链表和翻转后的后半部分链表交替合并
ListNode *p1 = head, *p2 = mid;
while(p1 != nullptr && p2 != nullptr) {
ListNode *tmp1 = p1->next, *tmp2 = p2->next;
p1->next = p2;
p2->next = tmp1;
p1 = tmp1;
p2 = tmp2;
}
}
private:
ListNode* reverse(ListNode* head) {
ListNode* pre = nullptr, *next = nullptr;
ListNode* cur = head;
while(cur != nullptr) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
public class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null) {
return;
}
// 找到链表中点并将后半部分链表翻转
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode mid = slow.next;
slow.next = null;
mid = reverse(mid);
// 将前半部分链表和翻转后的后半部分链表交替合并
ListNode p1 = head, p2 = mid;
while (p1 != null && p2 != null) {
ListNode tmp1 = p1.next, tmp2 = p2.next;
p1.next = p2;
p2.next = tmp1;
p1 = tmp1;
p2 = tmp2;
}
}
private ListNode reverse(ListNode head) {
ListNode pre = null, next = null;
ListNode cur = head;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
func reorderList(head *ListNode) {
if head == nil || head.Next == nil {
return
}
// 找到链表中点并将后半部分链表翻转
slow, fast := head, head
for fast.Next != nil && fast.Next.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
mid := slow.Next
slow.Next = nil
mid = reverse(mid)
// 将前半部分链表和翻转后的后半部分链表交替合并
p1, p2 := head, mid
for p1 != nil && p2 != nil {
tmp1, tmp2 := p1.Next, p2.Next
p1.Next = p2
p2.Next = tmp1
p1 = tmp1
p2 = tmp2
}
}
func reverse(head *ListNode) *ListNode {
var pre, next *ListNode
cur := head
for cur != nil {
next = cur.Next
cur.Next = pre
pre = cur
cur = next
}
return pre
}
148.排序链表
给你链表的头结点head,请将其按 升序 排列并返回 排序后的链表 。
![](https://assets.leetcode.com/uploads/2020/09/14/sort_list_1.jpg)
解题思路
数组的排序都很熟悉,有快排,归并排序,堆排这三种思路,但这三种方法不一定都适合链表排序,快排和堆排实现都需要通过数组下标访问元素,而这点链表做不到。可以使用归并排序算法。详细步骤如下:
分割链表
- 使用快慢指针法找到链表的中点:创建两个指针
slow
和fast
,初始时都指向链表头节点head
。同时移动这两个指针,slow
指针每次移动一步,fast
指针每次移动两步。当fast
指针到达链表尾部时,slow
指针恰好位于链表的中点。 - 断开链表:将链表从中点处分成两个子链表。为此,创建一个新的指针
prev
,初始化为None
。在遍历链表时,将prev
的next
指针设置为None
,从而断开链表。
递归排序子链表
- 对于每个子链表,递归执行归并排序。递归的基本情况是链表长度为 1 或 0,此时链表已经是有序的,直接返回。
合并子链表
- 使用双指针法合并两个有序子链表。创建两个指针
p1
和p2
,分别指向两个子链表的头节点。同时遍历两个子链表,将较小的节点加入新链表,并更新相应的指针。
class Solution {
public:
ListNode* merge(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* tail = &dummy;
while (l1 && l2) {
if (l1->val < l2->val) {
tail->next = l1;
l1 = l1->next;
} else {
tail->next = l2;
l2 = l2->next;
}
tail = tail->next;
}
tail->next = l1 ? l1 : l2;
return dummy.next;
}
ListNode* findMid(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
ListNode* prev = nullptr;
while (fast && fast->next) {
prev = slow;
slow = slow->next;
fast = fast->next->next;
}
if (prev) prev->next = nullptr;
return slow;
}
ListNode* sortList(ListNode* head) {
if (!head || !head->next) {
return head;
}
ListNode* mid = findMid(head);
ListNode* l1 = sortList(head);
ListNode* l2 = sortList(mid);
return merge(l1, l2);
}
};
public class Solution {
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
tail.next = l1;
l1 = l1.next;
} else {
tail.next = l2;
l2 = l2.next;
}
tail = tail.next;
}
tail.next = (l1 != null) ? l1 : l2;
return dummy.next;
}
public ListNode findMid(ListNode head) {
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
if (prev != null) prev.next = null;
return slow;
}
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode mid = findMid(head);
ListNode l1 = sortList(head);
ListNode l2 = sortList(mid);
return merge(l1, l2);
}
}
func merge(l1, l2 *ListNode) *ListNode {
dummy := &ListNode{Val: 0}
tail := dummy
for l1 != nil && l2 != nil {
if l1.Val < l2.Val {
tail.Next = l1
l1 = l1.Next
} else {
tail.Next = l2
l2 = l2.Next
}
tail = tail.Next
}
if l1 != nil {
tail.Next = l1
} else {
tail.Next = l2
}
return dummy.Next
}
func findMid(head *ListNode) *ListNode {
slow := head
fast := head
var prev *ListNode
for fast != nil && fast.Next != nil {
prev = slow
slow = slow.Next
fast = fast.Next.Next
}
if prev != nil {
prev.Next = nil
}
return slow
}
func sortList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
mid := findMid(head)
l1 := sortList(head)
l2 := sortList(mid)
return merge(l1, l2)
}