emmm,鏈表刷完,感悟挺多的。
如果是對鏈表節點直接利用的話,是要小心成環的,因爲一個節點那可不是你眼裏的一個節點,人家可能是一桶節點。
這些天做題我可算真切感受到了。
第一題:合併兩個有序鏈表
將兩個升序鏈表合併爲一個新的升序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
示例:
輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/merge-two-sorted-lists
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
第二題:迴文鏈表
請判斷一個鏈表是否爲迴文鏈表。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
進階:
你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/palindrome-linked-list
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
第三題:環型鏈表
給定一個鏈表,判斷鏈表中是否有環。
爲了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。
示例 2:
輸入:head = [1,2], pos = 0
輸出:true
解釋:鏈表中有一個環,其尾部連接到第一個節點。
示例 3:
輸入:head = [1], pos = -1
輸出:false
解釋:鏈表中沒有環。
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/linked-list-cycle
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
我的題解(1)
在吃過多次鏈表成環的虧之後,我學聰明瞭。
#include<iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
//////////創建結點/////////
ListNode* creat(int data)
{
ListNode* p = new ListNode(NULL);
p->val = data;
p->next = NULL;
return p;
}
ListNode* my_merge(ListNode* l1, ListNode* l2)
{
ListNode* head = l1; //留住頭結點
while (l1->next != NULL && l2 != NULL)
{
//默認l1的頭比l2的小
if (l1->val <= l2->val && l1->next->val>l2->val) //將新節點插入
{
ListNode* temp = creat(l2->val);
temp->next = l1->next;
l1->next = temp;
l1 = l1->next;
l2 = l2->next;
}
else
{
l1 = l1->next;
}
}
//l1走完,l2還沒完
if (l1->next == NULL && l2 != NULL)
{
l1->next = l2;
}
return head;
}
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
if(l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
ListNode *head = NULL;
if (l1->val < l2->val)
head = my_merge(l1,l2);
else
head = my_merge(l2,l1);
return head;
}
int main()
{
ListNode* a = new ListNode(1);
ListNode* b = new ListNode(3);
ListNode* c = new ListNode(4);
// ListNode* d = new ListNode(8);
ListNode* e = new ListNode(1);
ListNode* f = new ListNode(2);
ListNode* g = new ListNode(4);
// ListNode* h = new ListNode(9);
a->next = b;
b->next = c;
// c->next = d;
e->next = f;
f->next = g;
// g->next = h;
ListNode* i = mergeTwoLists(e,a);
while (i != NULL)
{
cout << i->val;
i = i->next;
}
}
我的題解(2)
不得不說,官方題解秀。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int len;
bool isPalindrome(ListNode* head) {
if(head == NULL || head->next == NULL) {
return true;
}
len = 0;
ListNode* re = reLink(head);
int length = 0;
while(head != NULL) {
if(head->val != re->val)
return false;
re = re->next;
head = head->next;
length++;
if(length > len/2)
break;
}
return true;
}
ListNode* reLink(ListNode* head) {
ListNode* temp = head;
ListNode* re = NULL;
while(temp){
ListNode* node = new ListNode(temp->val);
node->next = re;
re = node;
temp = temp->next;
len++;
}
return re;
}
};
我的題解(3)
先看上面這篇。
掌握了方法,簡單的很。
bool hasCycle(ListNode* head)
{
if (head == NULL || head->next == NULL)
return false;
ListNode* fast = head;
ListNode* slow = head;
fast = fast->next->next;
while (fast!=NULL && fast->next != NULL && fast!=slow)
{
slow = slow->next;
fast = fast->next->next;
}
if (fast == slow)
return true;
else
return false;
}
官方題解(1)
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
else if (l2 == null) {
return l1;
}
else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}
else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
> 作者:LeetCode-Solution
> 鏈接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
> 來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
官方題解(2)
方法三:
避免使用 O(n)O(n) 額外空間的方法就是改變輸入。
我們可以將鏈表的後半部分反轉(修改鏈表結構),然後將前半部分和後半部分進行比較。比較完成後我們應該將鏈表恢復原樣。雖然不需要恢復也能通過測試用例,因爲使用該函數的人不希望鏈表結構被更改。
算法:
我們可以分爲以下幾個步驟:
找到前半部分鏈表的尾節點。
反轉後半部分鏈表。
判斷是否爲迴文。
恢復鏈表。
返回結果。
執行步驟一,我們可以計算鏈表節點的數量,然後遍歷鏈表找到前半部分的尾節點。
或者可以使用快慢指針在一次遍歷中找到:慢指針一次走一步,快指針一次走兩步,快慢指針同時出發。當快指針移動到鏈表的末尾時,慢指針到鏈表的中間。通過慢指針將鏈表分爲兩部分。
若鏈表有奇數個節點,則中間的節點應該看作是前半部分。
步驟二可以使用在反向鏈表問題中找到解決方法來反轉鏈表的後半部分。
步驟三比較兩個部分的值,當後半部分到達末尾則比較完成,可以忽略計數情況中的中間節點。
步驟四與步驟二使用的函數相同,再反轉一次恢復鏈表本身。
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode/
來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
官方題解(3)
和我的一樣。
總結:
鏈表,小心成環,每個節點到底隱藏了多少,需要我們去畫圖縷清楚。
然後,推薦環形鏈表裏的那篇博客>>l鏈表誤成環