總結自:https://www.bilibili.com/video/BV1jt411J7tC
19. Remove Nth Node From End of List
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
Follow up:
Could you do this in one pass?
思路:
雙指針,因爲要刪除倒數第n個節點,那麼就要找到倒數第n+1個節點,所以其中一個指針先向右移動n個節點,這樣當靠右的節點到達鏈表尾的時候,另一個指針即指向倒數第n+1個節點
要點:
ListNode(int x) : val(x), next(NULL) {} // 用來初始化
auto dummy = new ListNode(-1); // auto會根據等號右邊的值的類型對確定變量的類型
ListNode* dummy = new ListNode(-1); // 跟上一條等價
因爲可能刪除的是頭節點,因此我們創建一個虛擬的節點指向頭節點,並且最終返回虛擬節點的下一個節點,這樣當被刪除的是頭節點時也不需要特殊判斷
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
auto dummy = new ListNode(-1);
dummy->next = head;
auto first = dummy, second = dummy;
while(n--) first = first->next;
while(first->next)
{
first = first->next;
second = second->next;
}
second->next = second->next->next;
return dummy->next;
}
};
237. Delete Node in a Linked List
Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
Given linked list – head = [4,5,1,9], which looks like following:
Example 1:
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function.
Example 2:
Input: head = [4,5,1,9], node = 1
Output: [4,5,9]
Explanation: You are given the third node with value 1, the linked list should become 4 -> 5 -> 9 after calling your function.
Note:
The linked list will have at least two elements.
All of the nodes’ values will be unique.
The given node will not be the tail and it will always be a valid node of the linked list.
Do not return anything from your function.
思路:一般要刪除一個節點,我們要找到該節點的前一個節點,但這道題只給出要刪除的節點,所以我們複製該節點的後一個節點的值,然後刪除後一個節點,這樣從整個鏈表上看就好像是刪除了該節點
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
// 上面兩句可以簡寫爲
// *(node) = *(node->next);
}
};
83. Remove Duplicates from Sorted List
Given a sorted linked list, delete all duplicates such that each element appear only once.
Example 1:
Input: 1->1->2
Output: 1->2
Example 2:
Input: 1->1->2->3->3
Output: 1->2->3
思路:遍歷一遍,如果該節點的值和下一個節點的值相同,就刪去下一個節點
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
auto temp = head;
while(temp)
{
if(temp->next && temp->val == temp->next->val) // 注意判下個節點是否爲空
temp-> next = temp->next->next;
else
// 只有當前後兩個節點值都不同時才指向下一個節點
// 否則如果再下一個節點的值仍然跟前兩個值相等,就會出錯
temp = temp->next;
}
return head;
}
};
61. Rotate List
Given a linked list, rotate the list to the right by k places, where k is non-negative.
Example 1:
Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL
Example 2:
Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL
思路:旋轉k次,相當於以倒數第k個節點當頭節點,鏈表尾指向原先的頭節點,因此可以用19. Remove Nth Node From End of List的雙指針方法定位兩個目標節點,由於k可能很大,因此需要先取模
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(!head) return NULL; // 判空
int n = 0;
for(auto p = head; p; p = p->next) n++;
k %= n;
auto left = head, right = head;
while(k--) right = right->next;
while(right->next)
{
left = left->next;
right = right->next;
}
right->next = head; // 鏈表末尾指向原先的頭
head = left->next; // 新的頭節點
left->next = NULL; // 新的鏈表尾
return head;
}
};
24. Swap Nodes in Pairs
Given a linked list, swap every two adjacent nodes and return its head.
You may not modify the values in the list’s nodes, only nodes itself may be changed.
Example:
Given 1->2->3->4, you should return the list as 2->1->4->3.
思路:頭節點有變化,因此用一個虛擬節點指向頭節點,用臨時節點p遍歷鏈表,用a和b分別表示p後面兩個要交換的節點,交換結束後p指向a,繼續交換後兩個節點,如果長度爲奇數,那最後一個節點不做改動
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
auto dummy = new ListNode(-1);
dummy->next = head;
for(auto p = dummy; p->next && p->next->next;)
{
auto a = p->next, b = p->next->next;
p->next = b;
a->next = b->next;
b->next = a;
p = a;
}
return dummy->next; // 第一次循環時p和dummy指向同一個地址
// 因此p->next的改變相當於改變dummy->next
// 這跟int a = b,a改變後b不變不同
}
};
206. Reverse Linked List
Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Follow up:
A linked list can be reversed either iteratively or recursively. Could you implement both?
思路:類似於以c爲媒介,交互a和b的值
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head) return NULL; // 判空
auto a = head, b = head->next;
head->next = NULL;
while(b) // b爲空時,由於a在b的左側,則此時a爲頭節點
{
auto c = b->next;
b->next = a;
a = b;
b = c;
}
return a;
}
};
92. Reverse Linked List II
Reverse a linked list from position m to n. Do it in one-pass.
Note: 1 ≤ m ≤ n ≤ length of list.
Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
思路:
由於頭節點可能出現變化,使用一個虛擬節點
1 -> 2 -> 3 -> 4 -> 5 -> NULL m = 2 n = 4
a b d c
a節點和c節點分別在要反轉的鏈表兩側,我們先用206. Reverse Linked List的方法把d到d之間的鏈表反轉,接着a節點的next指向d(1->4),b節點的next指向c(2->5)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(m == n) return head; // 特殊情況
auto dummy = new ListNode(-1);
dummy->next = head;
auto a = dummy, d = dummy;
for(int i = 0; i < m - 1; i++) a = a->next;
for(int i = 0; i < n; i++) d = d->next;
auto b = a->next, c = d->next;
for(auto p = b, q = b->next; q != c;)
{
auto o = q->next;
q->next = p;
p = q;
q = o;
}
b->next = c;
a->next = d;
return dummy->next;
}
};
160. Intersection of Two Linked Lists
Write a program to find the node at which the intersection of two singly linked lists begins.
For example, the following two linked lists:
begin to intersect at node c1.
思路:設A的頭節點到相交節點的長度爲a(暫且假設相交),B的頭節點到相交節點的長度爲b,共同鏈表的長度爲c
節點p從A頭節點開始出發,走到鏈表尾之後轉到B的頭節點繼續走,走到相交節點,則一共走了a+c+b個節點
節點q從B頭節點開始出發,走到鏈表尾之後轉到A的頭節點繼續走,走到相交節點,則一共走了a+b+c個節點
所以我們發現,只要p、q分別從兩個鏈表頭往下遍歷,每次各自指向下一個節點,並在走到鏈表尾之後轉向另一條鏈表繼續遍歷,如果兩條鏈表有交點,則p、q必定在交點處相遇,即節點p == 節點q,爲同一個節點,因爲此時它們都走了a+b+c個節點,當然如果恰好a==b,則它們在第一次經過相交點時就會相遇
而如果兩條鏈表沒有交點,則在走完a+b個節點後,p和q分別爲NULL,當然此時也滿足p == q,但返回的結果時NULL
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
auto p = headA, q = headB;
while(p != q)
{
if(p) p = p->next;
else p = headB;
if(q) q = q->next;
else q = headA;
}
return p;
}
};
142. Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
Note: Do not modify the linked list.
思路:快慢指針
假設有環,環的入口爲b點,head(即a點)到b的距離爲x
在head即a點設置快慢指針各一個,快指針一次移動兩個節點,慢指針一次一個,我們假設慢指針移動到b時,快指針移動到c‘處(可能快指針已經繞環很多圈),設此時快指針到b的距離爲y,然後繼續移動,因爲快指針的移動速度是慢指針移動速度的兩倍,慢指針繼續移動y個節點,快指針移動2y個節點,所以它們相遇的點c跟c’是對稱的(都距離b點y個節點)
第一次相遇以後,將慢指針放回到head,即a點,然後兩個指針都以每次一個節點的速度向前移動,它們再次相遇時的點就是環的入口
解釋:因爲慢指針第一次到達b點時,快指針已經移動了2x個節點,即快指針從b點開始移動x個節點以後會停留在c‘處,慢指針第二次到達b點時,由於快指針也是每次一個節點,因此也移動了x個節點,但此時的起點是c,由於c和c’是對稱的,相當於我們把原先的起點b向前移動y個節點到c,那麼原先的終點c’也隨之向前移動y個節點,恰好是環的入口b
/**
* 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) {
auto fast = head, slow = head;
while(fast) // 如果退出循環,說明有節點的next指向NULL,即沒有環
{
slow = slow->next;
fast = fast->next;
if(fast) fast = fast->next;
else break;
if(fast == slow) // 第一次相遇以後
{
slow = head;
while(slow != fast)
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return NULL;
}
};
148. Sort List
Sort a linked list in O(n log n) time using constant space complexity.
Example 1:
Input: 4->2->1->3
Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0
Output: -1->0->3->4->5
思路:
要求時間複雜度O(n log n),常數空間,如果使用快速排序等,遞歸時用到系統棧,則空間爲O(log n)
使用歸併排序的方法,不用遞歸,循環log n次,每次處理n個數據,所以爲O(n log n)
比如第一次循環,兩個數一組,按升序排號,第二次循環四個數一組,前兩個數和後兩個數都已經是升序,將它們歸併以後,得到的四個數就是升序,再八個數一組……
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
auto dummy = new ListNode(-1);
dummy->next = head;
int n = 0;
for(auto p = head; p; p = p->next) n++;
// 歸併排序的思想
for(int i = 1; i < n; i *= 2) // 每次對2*i個數進行排序
{
auto cur = dummy;
for(int j = 0; j + i < n; j += i * 2)
{
auto left = cur->next, right = cur->next;
// left和right分別指向一組排好序的數字
for(int k = 0; k < i; k++) right = right->next;
int l = 0, r = 0;
// 進行歸併
while(l < i && r < i && right)
if(left->val <= right->val)
{
cur->next = left;
cur = left;
left = left->next;
l++;
}
else
{
cur->next = right;
cur = right;
right = right->next;
r++;
}
// 結束後可能有一組數字還有剩餘
while(l < i)
{
cur->next = left;
cur = left;
left = left->next;
l++;
}
// 有可能右邊一組的長度不足
while(r < i && right)
{
cur->next = right;
cur = right;
right = right->next;
r++;
}
// 歸併結束後,cur指向下一組要歸併的數據的前一個節點
// 這樣後一組2*i個數據排序時left和right都指向這2*i個節點的第一個節點
cur->next = right;
}
}
return dummy->next;
}
};