分列如下:
- 142.Linked List Cycle II
- 148.Sort List
- 143.Reorder List
142. Linked List Cycle II
https://leetcode.com/problems/linked-list-cycle-ii/description/
题意
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?
思路
O(n)时间复杂度,O(1)空间复杂度就找到了链表中环的第一个node。拍案叫绝!解析参考这里https://www.cnblogs.com/hiddenfox/p/3408931.html
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
do{
if(fast == NULL) return NULL;
fast = fast ->next;
slow = slow ->next;
if(fast == NULL) return NULL;
fast = fast->next;
if(fast == slow) break;
}while(true);
slow = head;
while(slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
148. Sort List
https://leetcode.com/problems/sort-list/description/
题意
给出一个单向链表,要求排序,时间复杂度为O(nlgn),空间复杂度为O(1)。
思路
一般的思路是归并排序,用到递归。这样,其实在运行的过程中,就需要建立函数栈,实际空间复杂度并不是O(1)。
令人拍案惊奇的一个方法就是用循环来代替递归,从而将空间复杂度真正降到O(1)。
参考https://leetcode.com/problems/sort-list/discuss/46712/Bottom-to-up(not-recurring)-with-o(1)-space-complextity-and-o(nlgn)-time-complextity
这个答案代码十分好的一点在于,将split和merge函数独立出来,因此思路十分清晰,读者第一眼就能知道思路。
参考代码
// 代码转载自https://leetcode.com/problems/sort-list/discuss/46712/Bottom-to-up(not-recurring)-with-o(1)-space-complextity-and-o(nlgn)-time-complextity
/**
* Merge sort use bottom-up policy,
* so Space Complexity is O(1)
* Time Complexity is O(NlgN)
* stable sort
*/
class Solution {
public:
ListNode *sortList(ListNode *head) {
if(!head || !(head->next)) return head;
//get the linked list's length
ListNode* cur = head;
int length = 0;
while(cur){
length++;
cur = cur->next;
}
ListNode dummy(0);
dummy.next = head;
ListNode *left, *right, *tail;
for(int step = 1; step < length; step <<= 1){
cur = dummy.next;
// 取地址,而不是引用,注意了
tail = &dummy;
while(cur){
left = cur;
right = split(left, step);
cur = split(right,step);
tail = merge(left, right, tail);
}
}
return dummy.next;
}
private:
/**
* Divide the linked list into two lists,
* while the first list contains first n ndoes
* return the second list's head
*/
ListNode* split(ListNode *head, int n){
//if(!head) return NULL;
for(int i = 1; head && i < n; i++) head = head->next;
if(!head) return NULL;
ListNode *second = head->next;
head->next = NULL;
return second;
}
/**
* merge the two sorted linked list l1 and l2,
* then append the merged sorted linked list to the node head
* return the tail of the merged sorted linked list
*/
ListNode* merge(ListNode* l1, ListNode* l2, ListNode* head){
ListNode *cur = head;
while(l1 && l2){
if(l1->val > l2->val){
cur->next = l2;
cur = l2;
l2 = l2->next;
}
else{
cur->next = l1;
cur = l1;
l1 = l1->next;
}
}
cur->next = (l1 ? l1 : l2);
while(cur->next) cur = cur->next;
return cur;
}
};
143. Reorder List
https://leetcode.com/problems/reorder-list/description/
题意
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes’ values.
For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.
题意
这是一道常规的题目
我们可以看到,我们需要三个操作就可以得到结果。分别是:
1. split, 将输入链表切成两半
2. reverse, 将后一半链表逆序
3. merge,将前一半数组和逆序后的后一半数组交替连接。
但是最美丽的地方在于,我们参考148. Sort List,将各个操作独立出来,形成极其漂亮,清晰的代码。
参考代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
if(!head || !head->next) return;
int len = 0;
ListNode* cur = head, *second;
while(cur != NULL){
len++;
cur = cur->next;
}
int lenOfFirst = len/2 + len%2;
second = split(head, lenOfFirst);
second = reverse(second);
merge(head, second);
return;
}
ListNode* split(ListNode* head, int lenOfFirst){
ListNode* second, *cur = head;
for(int i = 1; i < lenOfFirst; i++) {
cur = cur->next;
}
second = cur->next;
cur->next = NULL;
return second;
}
ListNode* reverse(ListNode* head) {
if(!head || !head->next) return head;
ListNode* cur = head->next, *tmp;
head->next = NULL;
while(cur != NULL) {
tmp = cur->next;
cur->next = head;
head = cur;
cur = tmp;
}
return head;
}
void merge(ListNode* first, ListNode* second) {
ListNode* cur = first;
first = first->next;
while(first) {
cur->next = second;
second = second->next;
cur = cur->next;
cur->next = first;
first = first->next;
cur = cur->next;
}
cur->next = first?first:second;
return;
}
};