來水一波吧,這兩天有事兒都沒寫這一部分的,有點難受。
前兩題都很基本,第三題還好啦。
這篇主要是關於鏈表的,所以我先放一個鏈表的基礎篇,今天整理的。
接下來如正題:
第一題 刪除指定節點
請編寫一個函數,使其可以刪除某個鏈表中給定的(非末尾)節點,你將只被給定要求被刪除的節點。
現有一個鏈表 – head = [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.
說明:
鏈表至少包含兩個節點。
鏈表中所有節點的值都是唯一的。
給定的節點爲非末尾節點並且一定是鏈表中的一個有效節點。
不要從你的函數中返回任何結果。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
第二題 刪除倒數第n個節點
給定一個鏈表,刪除鏈表的倒數第 n 個節點,並且返回鏈表的頭結點。
示例:
給定一個鏈表: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點後,鏈表變爲 1->2->3->5.
說明:
給定的 n 保證是有效的。
進階:
你能嘗試使用一趟掃描實現嗎?
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
第三題 翻轉鏈表
反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進階:
你可以迭代或遞歸地反轉鏈表。你能否用兩種方法解決這道題?
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/reverse-linked-list
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
我的題解(1)
濫竽充數一下
void deleteNode(ListNode* node) {
// write your code here
if(node==NULL) return;
if(node->next==NULL)
{
node=NULL;
return;
}
node->val=node->next->val;
node->next=node->next->next;
}
我的題解(2)
這題難度居然能排在中等。。。
還是濫竽充數一下。
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(!head) return NULL;
ListNode* new_head = new ListNode(0);
new_head->next = head;
ListNode* slow = new_head, *fast = new_head;
for(int i = 0;i<n;++i){ //fast先移動n
fast = fast->next;
}
if(!fast) return new_head->next;
while(fast->next){ //一起移動
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return new_head->next;
}
我的題解(3)
這題有點意思,重點講這題吧
一開始我的想法是這樣的:先遍歷一遍,將鏈表中的值都取出來,然後逆向插回去,不過這樣要遍歷兩遍,於是我就想一遍實現。
我的想法是這樣的:頭向後遍歷,每次將當前遍歷到的尾部節點提取出來,放到最前面,實現逆轉乾坤。
但是,想法總是好的。
先看我的第一個實驗:
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
}; //通用
//ListNode* reverseList(ListNode* head)
//{
// ListNode* node_temp;
// ListNode* new_head;
//
// node_temp = head;
// //遍歷一個節點,就把它拿下來放到頭去
// while (head->next != NULL)
// {
// //先考慮只又兩個節點的情況
// head = head->next;
// new_head = head;
// new_head->next = node_temp;
// node_temp = new_head;
// }
// return new_head;
//}
我也不多說,爲什麼失敗,要是一眼看出來的話,容我呼你一聲大神。反正這失敗我是無語了。
再看第二次,算了我還是說一下上面那個。
我想原地逆置,然後一不小心,成環了。。。。。。。
於是我就換了個思路,用兩條鏈表,一個原鏈表,一個鏈棧。
然而,想法還是好的。
//ListNode* reverseList(ListNode* head)
//{
// ListNode* node_temp = new ListNode(NULL);
// ListNode* new_head = new ListNode(NULL); //鏈棧的頭
//
// //遍歷一個節點,就把它拿下來放到頭去
// while (head != NULL)
// {
// node_temp = head; //先將節點取出
// //先考慮只又兩個節點的情況
// head = head->next; //這個不放這裏又成環了
//
// node_temp->next = new_head;
// new_head= node_temp;
// }
// return new_head;
//}
哎,要是一眼沒看出來哪裏出問題了,那咱倆水平半斤八兩。
這時候,我的好兄弟一直喊我用頭插法,我不以爲然,讓他給我發過來瞅瞅。
在我看之前,我好像發現了什麼。於是我就把上面的代碼稍微調了一下。。。
成功了。。。
ListNode* reverseList(ListNode* head)
{
ListNode* node_temp = NULL; //這裏設爲NULL
ListNode* new_head = NULL; //鏈棧的頭
//遍歷一個節點,就把它拿下來放到頭去
while (head != NULL)
{
node_temp = head; //先將節點取出
//先考慮只又兩個節點的情況
head = head->next; //這個不放這裏又成環了
node_temp->next = new_head;
new_head= node_temp;
}
return new_head;
}
ListNode* reverseList(ListNode* head)
{
ListNode* node_temp = NULL; //這裏設爲NULL
ListNode* new_head = NULL; //鏈棧的頭
//遍歷一個節點,就把它拿下來放到頭去
while (head != NULL)
{
node_temp = head; //先將節點取出
//先考慮只又兩個節點的情況
head = head->next; //這個不放這裏又成環了
node_temp->next = new_head;
new_head= node_temp;
}
return new_head;
}
成功就算了,我回頭一看他的“頭插法”,我都懵了,怎麼一模一樣。。。。。
官方題解(3)
假設存在鏈表 1 → 2 → 3 → Ø,我們想要把它改成 Ø ← 1 ← 2 ← 3。
在遍歷列表時,將當前節點的 next 指針改爲指向前一個元素。由於節點沒有引用其上一個節點,因此必須事先存儲其前一個元素。在更改引用之前,還需要另一個指針來存儲下一個節點。不要忘記在最後返回新的頭引用!
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
複雜度分析
時間複雜度:O(n),假設 n 是列表的長度,時間複雜度是 O(n)。
空間複雜度:O(1)。
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/
來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
方法二:遞歸
遞歸版本稍微複雜一些,其關鍵在於反向工作。假設列表的其餘部分已經被反轉,現在我該如何反轉它前面的部分?
假設列表爲:
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
複雜度分析
時間複雜度:O(n)O(n),假設 nn 是列表的長度,那麼時間複雜度爲 O(n)O(n)。
空間複雜度:O(n)O(n),由於使用遞歸,將會使用隱式棧空間。遞歸深度可能會達到 nn 層。
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/
來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。