Leetcode ---- 連結串列簡單題
複習了一下連結串列。下面做了一些簡單題。
237. 刪除連結串列中的元素
題目:
請編寫一個函式,使其可以刪除某個連結串列中給定的(非末尾)節點,你將只被給定要求被刪除的節點。
現有一個連結串列 -- head = [4,5,1,9],它可以表示為:
4 -> 5 -> 1 -> 9
示例 1:
輸入: head = [4,5,1,9], node = 5 輸出: [4,1,9] 解釋: 給定你連結串列中值為 5 的第二個節點,那麼在呼叫了你的函式之後,該連結串列應變為 4 -> 1 -> 9.
示例 2:
輸入: head = [4,5,1,9], node = 1 輸出: [4,5,9] 解釋: 給定你連結串列中值為 1 的第三個節點,那麼在呼叫了你的函式之後,該連結串列應變為 4 -> 5 -> 9.
說明:
- 連結串列至少包含兩個節點。
- 連結串列中所有節點的值都是唯一的。
- 給定的節點為非末尾節點並且一定是連結串列中的一個有效節點。
- 不要從你的函式中返回任何結果。
思路:
這道題很巧妙,函式只給了一個結點。題目要求是刪除該結點。那麼我們只需要將上個結點的後繼指向下一個結點。然而上一結點的資訊我們並不知道。所以,我們只能將這一結點替代下一結點,下一結點沒有結點指向。
程式:
/** * 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) { ListNode *p = node->next; node->val = p->val; node->next = p->next; } };
203. 移除連結串列元素
題目:
刪除連結串列中等於給定值 val 的所有節點。
示例:
輸入: 1->2->6->3->4->5->6, val = 6 輸出: 1->2->3->4->5
思路:
由於這是一個單鏈表,刪除節點需要上一非目標節點指向該節點後續的非目標節點,因此,需要兩個指標,指標一是隻指向非目標節點的,而指標二是用來判斷節點的。
程式:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *res = new ListNode(-1);
ListNode *p = res;
ListNode *q = head;
while (q != NULL){
if (q->val != val){
p->next = q;
p = p->next;
}
q = q->next;
}
p->next = NULL;
return res->next;
}
};
83. 刪除排序連結串列中的重複元素
題目:
給定一個排序連結串列,刪除所有重複的元素,使得每個元素只出現一次。
示例 1:
輸入: 1->1->2 輸出: 1->2
示例 2:
輸入: 1->1->2->3->3 輸出: 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) {
ListNode *p = head;
if (head == nullptr){
return head;
}
while (p->next){
if (p->val == p->next->val){
p->next = p->next->next;
}
else{
p = p->next;
}
}
return head;
}
};
876. 連結串列的中間結點
題目:
給定一個帶有頭結點 head
的非空單鏈表,返回連結串列的中間結點。
如果有兩個中間結點,則返回第二個中間結點。
示例 1:
輸入:[1,2,3,4,5] 輸出:此列表中的結點 3 (序列化形式:[3,4,5]) 返回的結點值為 3 。 (測評系統對該結點序列化表述是 [3,4,5])。 注意,我們返回了一個 ListNode 型別的物件 ans,這樣: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
輸入:[1,2,3,4,5,6] 輸出:此列表中的結點 4 (序列化形式:[4,5,6]) 由於該列表有兩個中間結點,值分別為 3 和 4,我們返回第二個結點。
提示:
- 給定連結串列的結點數介於
1
和100
之間。
思路:
這道題求中點,很容易想到快慢指標,速度快一倍,當快指標指向NULL時,慢指標正好指向中點。
程式:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *fast,*slow;
fast = head;
slow = head;
while (fast != NULL && fast->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
141. 環形連結串列
題目:
給定一個連結串列,判斷連結串列中是否有環。
進階:
你能否不使用額外空間解決此題?
思路:
依題意,我們可知道,該環只能在連結串列末尾的,不可能在中間和首。那麼,可以想象,當一個指標進入環後會無限迴圈下去。我們只需再放一個指標從頭進入,且速度比第一個指標慢即可。它們最終會在環內相遇。若沒環,則指標會指向NULL。
程式:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast,*slow;
fast = head;
slow = head;
while (fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if (fast == slow){
return true;
}
}
return false;
/* if (!head || !head->next) // 判斷是迴圈連結串列,理解錯誤
return false;
ListNode *p = head;
while (p->next){
if (p->next == head)
return true;
p = p->next;
}
return false;
*/
}
};
160. 相交連結串列
題目:
編寫一個程式,找到兩個單鏈表相交的起始節點。
例如,下面的兩個連結串列:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
在節點 c1 開始相交。
注意:
- 如果兩個連結串列沒有交點,返回
null
. - 在返回結果後,兩個連結串列仍須保持原有的結構。
- 可假定整個連結串列結構中沒有迴圈。
- 程式儘量滿足 O(n) 時間複雜度,且僅用 O(1) 記憶體。
思路:
這題有兩個思路:
1. 得到兩個連結串列的長度,然後刪去長連結串列的頭,使得兩個連結串列相等。隨後從頭開始比對。
2. 若兩連結串列長度不相等,則正常比對到NULL也不會得到相等的。然而,兩個長度不一的連結串列各自加上對方,則會得到兩個相等長度的連結串列。由此,我們可以 第一次遇到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) {
ListNode *p,*q;
p = headA;
q = headB;
while (p != q){
if (p == NULL){
p = headB;
}
else{
p = p->next;
}
if (q == NULL){
q = headA;
}
else{
q = q->next;
}
}
return p;
/* int i = 0,j = 0;
ListNode *p = headA,*q = headB;
if (p == NULL || q == NULL)
return NULL;
while (p != NULL){
p = p->next;
i++;
}
while (q != NULL){
q = q->next;
j++;
}
int dis = i - j;
p = headA;
q = headB;
if (dis >= 0){
while (dis != 0 && p != NULL){
p = p->next;
dis--;
}
}
else{
while (dis != 0 && q != NULL){
q = q->next;
dis++;
}
}
while (p != NULL){
if (p == q){
return p;
}
p = p->next;
q = q->next;
}
return NULL;*/
}
};
21. 合併兩個有序連結串列
題目:
將兩個有序連結串列合併為一個新的有序連結串列並返回。新連結串列是通過拼接給定的兩個連結串列的所有節點組成的。
示例:
輸入:1->2->4, 1->3->4 輸出:1->1->2->3->4->4
思路:
1. 直接建立一個新連結串列,比對兩條連結串列,小的往裡面放即可。
2. 遞迴
程式:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *head = new ListNode(-1);
ListNode *p = head;
if (l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
while (l1 != NULL && l2 != NULL){
if (l1->val < l2->val){
p->next = l1;
p = p->next;
l1 = l1->next;
}
else{
p->next = l2;
p = p->next;
l2 = l2->next;
}
}
if (l1 == NULL && l2 != NULL){
p->next = l2;
}
if (l2 == NULL && l1 != NULL){
p->next = l1;
}
return head->next;
/* if (l1 == NULL) // 遞迴
return l2;
if (l2 == NULL)
return l1;
if (l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}
else{
l2->next = mergeTwoLists(l2->next,l1);
return l2;
}*/
}
};
206. 反轉連結串列
題目:
反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL 輸出: 5->4->3->2->1->NULL
進階:
你可以迭代或遞迴地反轉連結串列。你能否用兩種方法解決這道題?
思路:
該題思路比較死板的方法就是建個數組(棧),先入再出。另一種就是用兩個指標,迴圈往回指即可。
程式:
/**
* 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 == NULL||head->next == NULL){
return head;
}
ListNode *ans = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return ans;
/* if (!head || !head->next)
return head;
ListNode *p = head;
ListNode *tmp,*q;
q = p->next;
p->next = NULL;
while (q){
tmp = q->next;
q->next = p;
p = q;
q = tmp;
}
return p;*/
}
};