链表 c语言动态内存管理中
链表结构无处不在
有fast bin这种单向链表
也有unsorted bin这种双向链表
我应该还是蛮熟悉的…
重点在于对指针的理解
做题过程中呢发现
核心算法是
双指针
那么
启动!
160.相交链表
双指针好吧
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution {public : ListNode *getIntersectionNode (ListNode *headA, ListNode *headB) { if (!headA || !headB) return nullptr ; ListNode* p1 = headA; ListNode* p2 = headB; while (p1 != p2){ p1 = (p1 ? p1->next : headB); p2 = (p2 ? p2->next : headA); } return p1; } };
206.反转链表
解法:
reverse !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : ListNode* reverseList (ListNode* head) { ListNode* prev = nullptr ; ListNode* cur = head; while (cur){ ListNode* tmp = cur->next; cur->next = prev; prev = cur; cur = tmp; } return prev; } };
234.回文链表
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution {public : bool isPalindrome (ListNode* head) { if (!head || !head->next) return true ; ListNode* slow = head; ListNode* fast = head; while (fast && fast->next){ slow = slow->next; fast = fast->next->next; } ListNode* prev = nullptr ; while (slow){ ListNode* next = slow->next; slow->next = prev; prev = slow; slow = next; } ListNode* left = head; ListNode* right = prev; while (right){ if (left->val != right->val){ return false ; } left = left->next; right = right->next; } return true ; } };
141.环形链表
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution {public : bool hasCycle (ListNode *head) { if (!head || !head->next) return false ; ListNode* slow = head; ListNode* fast = head; while (fast && fast->next){ slow = slow->next; fast = fast->next->next; if (slow == fast) return true ; } return false ; } };
142.环形链表II
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution {public : ListNode *detectCycle (ListNode *head) { if (!head || !head->next) return nullptr ; ListNode* slow = head; ListNode* fast = head; while (fast && fast->next){ slow = slow->next; fast = fast->next->next; if (slow == fast) break ; } if (!fast || !fast->next) return nullptr ; slow = head; while (slow != fast){ slow = slow->next; fast = fast->next; } return slow; } };
21.合并两个有序链表
解:
双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : ListNode* mergeTwoLists (ListNode* list1, ListNode* list2) { ListNode dummy (0 ) ; ListNode* cur = &dummy; while (list1 && list2){ if (list1->val <= list2->val){ cur->next = list1; list1 = list1->next; }else { cur->next = list2; list2 = list2->next; } cur = cur->next; } cur->next = list1 ? list1 : list2; return dummy.next; } };
2.两数相加
用链表逐位相加并维护进位,用dummy head简化边界处理 ,线性时间 构造结果链表~
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution {public : ListNode* addTwoNumbers (ListNode* l1, ListNode* l2) { ListNode dummy (0 ) ; ListNode* cur = &dummy; int carry = 0 ; while (l1 || l2 || carry) { int sum = carry; if (l1) { sum += l1->val; l1 = l1->next; } if (l2) { sum += l2->val; l2 = l2->next; } carry = sum / 10 ; cur->next = new ListNode (sum % 10 ); cur = cur->next; } return dummy.next; } };
19.删除链表的倒数第N个节点 还是通过虚拟头结点配合快慢指针 保持固定间距,在一次线性遍历中定位并删除倒数第 n 个节点,统一处理头结点等边界情况~
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution {public : ListNode* removeNthFromEnd (ListNode* head, int n) { ListNode dummy (0 ) ; dummy.next = head; ListNode* fast = &dummy; ListNode* slow = &dummy; for (int i = 0 ; i <= n; i++) { fast = fast->next; } while (fast) { fast = fast->next; slow = slow->next; } ListNode* del = slow->next; slow->next = del->next; delete del; return dummy.next; } };
24.两两交换链表中的节点 依旧通过引入虚拟头结点并维护前驱指针,每次对相邻两个节点进行指针重连,在一次线性遍历中完成成对交换并统一处理头结点变化~
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution {public : ListNode* swapPairs (ListNode* head) { ListNode dummy (0 ) ; dummy.next = head; ListNode* prev = &dummy; while (prev->next && prev->next->next) { ListNode* a = prev->next; ListNode* b = a->next; a->next = b->next; b->next = a; prev->next = b; prev = a; } return dummy.next; } };
25.K个一组翻转链表
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution {public : ListNode* reverseKGroup (ListNode* head, int k) { ListNode dummy (0 ) ; dummy.next = head; ListNode* prev = &dummy; while (true ) { ListNode* node = prev; for (int i = 0 ; i < k && node; i++) { node = node->next; } if (!node) break ; ListNode* curr = prev->next; ListNode* temp = curr->next; for (int i = 1 ; i < k; i++) { curr->next = temp->next; temp->next = prev->next; prev->next = temp; temp = curr->next; } prev = curr; } return dummy.next; } };
138.随机链表的复制
解法1:
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution {public : Node* copyRandomList (Node* head) { if (!head) return nullptr ; unordered_map<Node*, Node*> mp; Node* cur = head; while (cur) { mp[cur] = new Node (cur->val); cur = cur->next; } cur = head; while (cur) { mp[cur]->next = mp[cur->next]; mp[cur]->random = mp[cur->random]; cur = cur->next; } return mp[head]; } };
解法2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution {public : Node* copyRandomList (Node* head) { if (!head) return nullptr ; Node* cur = head; while (cur) { Node* copy = new Node (cur->val); copy->next = cur->next; cur->next = copy; cur = copy->next; } cur = head; while (cur) { if (cur->random) { cur->next->random = cur->random->next; } cur = cur->next->next; } cur = head; Node* newHead = head->next; while (cur) { Node* copy = cur->next; cur->next = copy->next; if (copy->next) { copy->next = copy->next->next; } cur = cur->next; } return newHead; } };
148.排序链表
解:
归并排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution {public : ListNode* merge (ListNode* l1, ListNode* l2) { ListNode dummy (0 ) ; ListNode* cur = &dummy; while (l1 && l2) { if (l1->val < l2->val) { cur->next = l1; l1 = l1->next; }else { cur->next = l2; l2 = l2->next; } cur = cur->next; } cur->next = l1 ? l1 : l2; return dummy.next; } ListNode* sortList (ListNode* head) { if (!head || !head->next) return head; ListNode* slow = head; ListNode* fast = head->next; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode* mid = slow->next; slow->next = nullptr ; ListNode* left = sortList (head); ListNode* right = sortList (mid); return merge (left, right); } };
23.合并K个升序链表
解:
小顶堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution {public : struct cmp { bool operator () (ListNode* a, ListNode* b) { return a->val > b->val; } }; ListNode* mergeKLists (vector<ListNode*>& lists) { priority_queue<ListNode*, vector<ListNode*>, cmp> pq; for (auto node : lists) { if (node) pq.push (node); } ListNode dummy (0 ) ; ListNode* cur = &dummy; while (!pq.empty ()) { ListNode* node = pq.top (); pq.pop (); cur->next = node; cur = cur->next; if (node->next) { pq.push (node->next); } } return dummy.next; } };
146.LRU缓存
解:
least recently used cache
哈希表 + 双向链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 class LRUCache {private : struct Node { int key; int val; Node* prev; Node* next; Node (int k,int v):key (k),val (v),prev (nullptr ),next (nullptr ){} }; unordered_map<int ,Node*> cache; int capacity; Node* head; Node* tail; public : LRUCache (int capacity) { this ->capacity = capacity; head = new Node (0 ,0 ); tail = new Node (0 ,0 ); head->next = tail; tail->prev = head; } void remove (Node* node) { node->prev->next = node->next; node->next->prev = node->prev; } void insert (Node* node) { node->next = head->next; node->prev = head; head->next->prev = node; head->next = node; } int get (int key) { if (cache.count (key) == 0 ) { return -1 ; } Node* node = cache[key]; remove (node); insert (node); return node->val; } void put (int key, int value) { if (cache.count (key)) { Node* node = cache[key]; node->val = value; remove (node); insert (node); }else { if (cache.size () == capacity) { Node* node = tail->prev; remove (node); cache.erase (node->key); } Node* node = new Node (key,value); cache[key] = node; insert (node); } } };