链表
链表题,多指针(反转链表),多虚拟头(分隔链表)
用集合,先把A链表存进集合,然后遍历B链表,每次判断节点是否在集合里,在的话就是第一个相交,用集合来判断链表公共元素问题太方便了
1 class Solution { 2 public: 3 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 unordered_set<ListNode*> s; 5 while(headA){ 6 s.insert(headA); 7 headA = headA->next; 8 9 10 } 11 while(headB){ 12 if(s.count(headB)){ 13 return headB; 14 } 15 headB = headB->next; 16 } 17 return NULL; 18 } 19 };
双指针数学构思,拼接,AB,BA,
View Code
View Code
View Code
View Code
View Code
1 class Solution { 2 public: 3 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 if (headA == nullptr || headB == nullptr) { 5 return nullptr; 6 } 7 ListNode *pA = headA, *pB = headB; 8 while (pA != pB) { 9 pA = pA == nullptr ? headB : pA->next; 10 pB = pB == nullptr ? headA : pB->next; 11 } 12 return pA; 13 } 14 }; 15 16 作者:LeetCode-Solution 17 链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/xiang-jiao-lian-biao-by-leetcode-solutio-a8jn/ 18 来源:力扣(LeetCode) 19 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目要求n(logn),所以这边考虑归并排序
先分,再合,合的话就是合并两个有序链表,和合并两个有序数组一样简单
1 class Solution { 2 public: 3 ListNode* sortList(ListNode* head) { 4 if (!head || !head->next) return head;//0个和1个数的情况 5 auto slow = head, fast = head; 6 while (fast->next && fast->next->next)//三个数则进入循环分割 7 slow = slow->next, fast = fast->next->next; 8 // 切链 9 fast = slow->next, slow->next = nullptr; 10 return merge(sortList(head), sortList(fast)); 11 } 12 13 ListNode* merge(ListNode* l1, ListNode* l2) { 14 ListNode* head = new ListNode(); 15 ListNode* ptr = head; 16 while (l1 && l2) { 17 auto &node = l1->val < l2->val ? l1 : l2;//&可以同步->next这个操作,其他添加和删除节点功能一样 18 ptr = ptr->next = node, node = node->next; 19 } 20 ptr->next = l1 ? l1 : l2; 21 return head->next; 22 } 23 };
存一个别人的七份简洁答案
1 class Solution { 2 public: 3 ListNode* sortList(ListNode* head) { 4 if (!head || !head->next) return head; 5 auto slow = head, fast = head; 6 while (fast->next && fast->next->next) 7 slow = slow->next, fast = fast->next->next; 8 // 切链 9 fast = slow->next, slow->next = nullptr; 10 return merge(sortList(head), sortList(fast)); 11 } 12 13 private: 14 ListNode* merge(ListNode* l1, ListNode* l2) { 15 ListNode sub(0), *ptr = ⊂ 16 while (l1 && l2) { 17 auto &node = l1->val < l2->val ? l1 : l2; 18 ptr = ptr->next = node, node = node->next; 19 } 20 ptr->next = l1 ? l1 : l2; 21 return sub.next; 22 } 23 }; 24 红黑树排序 25 利用STL里面的set容器底层是红黑树实现,来实现树排序 26 27 28 class Solution { 29 public: 30 ListNode* sortList(ListNode* head) { 31 multiset<int> worker; 32 auto sub = head; 33 while (sub) worker.insert(sub->val), 34 sub = sub->next; 35 sub = head; 36 for (auto &i : worker) 37 sub->val = i, sub = sub->next; 38 return head; 39 } 40 }; 41 堆排序 42 也是利用STL里面的优先队列底层是堆排序算法,来实现。 43 44 45 class Solution { 46 public: 47 ListNode* sortList(ListNode* head) { 48 priority_queue<int, vector<int>, greater<int>> worker; 49 auto sub = head; 50 while (sub) worker.push(sub->val), sub = sub->next; 51 sub = head; 52 while (sub) { 53 sub->val = worker.top(), worker.pop(); 54 sub = sub->next; 55 } 56 return head; 57 } 58 }; 59 以下代码是力扣因为时间过不了的代码,但是逻辑没问题。大家看看,当扩张思维了。 60 61 代码逻辑都是,把数组当成中间变量来做排序,再最终转化成链表: 62 链表->数组->链表 63 64 快排 65 66 class Solution { 67 public: 68 ListNode* sortList(ListNode* head) { 69 vector<ListNode*> worker; 70 ListNode temp(0), *ptr = head; 71 while (ptr) worker.push_back(ptr), ptr = ptr->next; 72 quickSort(worker, 0, worker.size() - 1); 73 ptr = &temp; 74 for (auto i : worker) ptr = ptr->next = i; 75 ptr->next = nullptr; 76 return temp.next; 77 } 78 79 private: 80 void quickSort(vector<ListNode*> &worker, int l, int r) { 81 if (l >= r) return; 82 int pivot = patition(worker, l, r); 83 quickSort(worker, l, pivot - 1); 84 quickSort(worker, pivot + 1, r); 85 } 86 87 int patition(vector<ListNode*> &worker, int l, int r) { 88 for (int i = l; i < r; ++i) { 89 if (worker[i]->val < worker[r]->val) 90 swap(worker[l++], worker[i]); 91 } 92 swap(worker[l], worker[r]); 93 return l; 94 } 95 }; 96 97 class Solution { 98 public: 99 ListNode* sortList(ListNode* head) { 100 vector<int> worker; 101 auto sub = head; 102 while (sub) worker.push_back(sub->val), 103 sub = sub->next; 104 quickSort(worker, 0, worker.size() - 1); 105 sub = head; 106 for (auto &i : worker) 107 sub->val = i, sub = sub->next; 108 return head; 109 } 110 111 private: 112 void quickSort(vector<int> &worker, int l, int r) { 113 if (l >= r) return; 114 int pivot = patition(worker, l, r); 115 quickSort(worker, l, pivot - 1); 116 quickSort(worker, pivot + 1, r); 117 } 118 119 int patition(vector<int> &worker, int l, int r) { 120 for (int i = l; i < r; ++i) { 121 if (worker[i] < worker[r]) 122 swap(worker[l++], worker[i]); 123 } 124 swap(worker[l], worker[r]); 125 return l; 126 } 127 }; 128 冒泡 129 130 class Solution { 131 public: 132 ListNode* sortList(ListNode* head) { 133 vector<ListNode*> worker; 134 ListNode temp(0), *ptr = head; 135 while (ptr) worker.push_back(ptr), ptr = ptr->next; 136 for (int i = worker.size() - 1; i >= 0; --i) { 137 for (int j = 0; j < i; ++j) 138 if (worker[j]->val > worker[j + 1]->val) 139 swap(worker[j], worker[j + 1]); 140 } 141 ptr = &temp; 142 for (auto i : worker) ptr = ptr->next = i; 143 ptr->next = nullptr; 144 return temp.next; 145 } 146 }; 147 148 作者:fengziL 149 链接:https://leetcode-cn.com/problems/sort-list/solution/7fen-ji-jian-cdai-ma-zhi-wei-zheng-li-si-wqr0/ 150 来源:力扣(LeetCode) 151 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目链接:142. 环形链表 II - 力扣(LeetCode) (leetcode-cn.com)
链表嘛,无非就那几种方法,玩不出什么花来,最多双指针或者三指针,差不多了,再难点就是快慢指针。
这道题先判断是否存在环,然后再求环的起点。
是否有环很好判断,难想到的就是求环起点,数学推导如下:
设head到环起点为a,环起点到环里快慢指针相遇点为b,相遇点到环起点为c,(环长b+c)则有
a+b+(b+c)*n = 2*(a+b)
化简得:a = (b+c)*(n-1)+c;
特殊值n=1理解的话,就是快指针只转了一圈多就相遇。此时a = c,意思是慢指针再走c距离到环起点,头指针同时走c距离,刚好也到环起点,相遇即是等式。
1 class Solution { 2 public: 3 ListNode *detectCycle(ListNode *head) { 4 ListNode * slow = head; 5 ListNode * fast = head; 6 while(fast!=nullptr&&fast->next!=nullptr){ 7 fast = fast->next->next; 8 slow = slow->next; 9 if(fast == slow){ 10 ListNode * pre = head; 11 while(pre != slow){ 12 pre = pre->next; 13 slow = slow->next; 14 } 15 return pre ; 16 } 17 } 18 return nullptr; 19 } 20 };
还有,慢指针一定是第一圈还没转完就和快指针相遇了,因为慢指针半圈,快指针转一圈,所以无论快指针在哪,最多慢指针转半圈就相遇了。
234. 回文链表 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool isPalindrome(ListNode* head) { 4 if (head == nullptr || head->next == nullptr) return true; 5 ListNode* slow = head; // 慢指针,找到链表中间分位置,作为分割 6 ListNode* fast = head; 7 while (fast && fast->next) {//12的话 ,1 2;123的话,1,23;1234的话,1 8 slow = slow->next; 9 fast = fast->next->next; 10 } 11 if(fast)//奇数,1 ,23,23变成3再反转 12 slow = slow->next; 13 14 ListNode* cur1 = head; // 前半部分 15 ListNode* cur2 = reverseList(slow); // 16 17 // 开始两个链表的比较 18 while (cur1&&cur2) { 19 if (cur1->val != cur2->val) return false; 20 cur1 = cur1->next; 21 cur2 = cur2->next; 22 } 23 return true; 24 } 25 // 反转链表 26 ListNode* reverseList(ListNode* head) { 27 ListNode* temp; // 保存cur的下一个节点 28 ListNode* cur = head; 29 ListNode* pre = nullptr; 30 while(cur) { 31 temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next 32 cur->next = pre; // 翻转操作 33 // 更新pre 和 cur指针 34 pre = cur; 35 cur = temp; 36 } 37 return pre; 38 } 39 };