算法总结 DAY_06
链表专题
删除链表中的节点
LeetCode 237. delete-node-in-a-linked-list
题目:
题解
和下一个节点交换
class Solution { public: void deleteNode(ListNode* node) { node->val = node->next->val; node->next = node->next->next; } };
|
复杂度分析
删除链表的倒数第 N 个结点
LeetCode 19. remove-nth-node-from-end-of-list
题目:
题解
计算链表长度
class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { int size = 0; ListNode* head1 = head; while(head1 != nullptr){ head1 = head1 -> next; size++; } if(size == n){ head = head->next; return head; } ListNode* head2 = head; for(int i = 1; i < size - n; i++){ head2 = head2->next; } head2->next = head2->next->next; ListNode* ans = head; return ans; } };
|
官方题解:
class Solution { public: int getLength(ListNode* head) { int length = 0; while (head) { ++length; head = head->next; } return length; }
ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* dummy = new ListNode(0, head); int length = getLength(head); ListNode* cur = dummy; for (int i = 1; i < length - n + 1; ++i) { cur = cur->next; } cur->next = cur->next->next; ListNode* ans = dummy->next; delete dummy; return ans; } };
|
复杂度分析
- 时间复杂度:O(L),其中 L 是链表的长度。
- 空间复杂度:O(1)。
栈
class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* dummy = new ListNode(0, head); stack<ListNode*> stk; ListNode* cur = dummy; while (cur) { stk.push(cur); cur = cur->next; } for (int i = 0; i < n; ++i) { stk.pop(); } ListNode* prev = stk.top(); prev->next = prev->next->next; ListNode* ans = dummy->next; delete dummy; return ans; } };
|
复杂度分析
- 时间复杂度:
O(L)
,其中 L 是链表的长度。
- 空间复杂度:
O(L)
,其中 L 是链表的长度。主要为栈的开销。
双指针
class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* dummy = new ListNode(0, head); ListNode* first = head; ListNode* second = dummy; for (int i = 0; i < n; ++i) { first = first->next; } while (first) { first = first->next; second = second->next; } second->next = second->next->next; ListNode* ans = dummy->next; delete dummy; return ans; } };
|
复杂度分析
- 时间复杂度:
O(L)
,其中 L是链表的长度。
- 空间复杂度:
O(1)
。
知识点拓展
链表
定义一个新节点,val
为0,next
为head。这样做是因为head节点也可能被删除,避免增加更多代码处理边界情况。
ListNode* dummy = new ListNode(0, head);
|
定义一个新节点,并且节点指向head。
删除排序链表中的重复元素
LeetCode 83. remove-duplicates-from-sorted-list
题目:
题解
一次遍历
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { ListNode* h = head; if(head == nullptr){ return head; } while(h->next){ if(h->val == h->next->val){ h->next = h->next->next; } else h = h->next; } return head; } };
|
复杂度分析
- 时间复杂度:
O(n)
,其中 n 是链表的长度。
- 空间复杂度:
O(1)
。
旋转链表
LeetCode 61. rotate-list
题目:
题解
闭合为环
class Solution { public: ListNode* rotateRight(ListNode* head, int k) { int size = 0; if(!head || head->next == nullptr) return head; ListNode* c = head; while(c != nullptr){ c = c -> next; size++; } if(k%size == 0) return head; ListNode* c1 = head; for(int i = 1; i < size-(k%size); i++){ c1 = c1->next; } ListNode* c2 = c1; ListNode* c3 = head; ListNode* ans = c1->next; for(int i = 0; i < k%size; i++){ c2 = c2->next; } c1->next = nullptr; c2->next = c3; return ans; } };
|
官方题解:
class Solution { public: ListNode* rotateRight(ListNode* head, int k) { if (k == 0 || head == nullptr || head->next == nullptr) { return head; } int n = 1; ListNode* iter = head; while (iter->next != nullptr) { iter = iter->next; n++; } int add = n - k % n; if (add == n) { return head; } iter->next = head; while (add--) { iter = iter->next; } ListNode* ret = iter->next; iter->next = nullptr; return ret; } };
|
复杂度分析
- 时间复杂度:
O(n)
,最坏情况下,我们需要遍历该链表两次。
- 空间复杂度:
O(1)
,我们只需要常数的空间存储若干变量。
两两交换链表中的节点
LeetCode 24. swap-nodes-in-pairs
题目:
题解
迭代
思路与算法
class Solution { public: ListNode* swapPairs(ListNode* head) { if(!head || head->next == nullptr) return head; ListNode* cur1 = head; ListNode* cur2 = head->next; ListNode* ans = head->next; while(cur1->next->next && cur2->next->next){ ListNode* temp1 = cur1->next->next; ListNode* temp2 = cur2->next->next; cur1->next = temp2; cur2->next = cur1; cur1 = temp1; cur2 = cur2->next->next; } if(cur1->next->next) cur1->next = cur1->next->next; else cur1->next = nullptr; cur2->next = cur1; return ans; } };
|
官方题解:
class Solution { public: ListNode* swapPairs(ListNode* head) { ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* temp = dummyHead; while (temp->next != nullptr && temp->next->next != nullptr) { ListNode* node1 = temp->next; ListNode* node2 = temp->next->next; temp->next = node2; node1->next = node2->next; node2->next = node1; temp = node1; } return dummyHead->next; } };
|
复杂度分析
- 时间复杂度:
O(n)
,其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
- 空间复杂度:
O(1)
。
递归
思路与算法
class Solution { public: ListNode* swapPairs(ListNode* head) { if (head == nullptr || head->next == nullptr) { return head; } ListNode* newHead = head->next; head->next = swapPairs(newHead->next); newHead->next = head; return newHead; } };
|
复杂度分析
- 时间复杂度:
O(n)
,其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
- 空间复杂度:
O(n)
,其中 n 是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。