leetcode 链表类型题总结
链表测试框架示例:
1 // leetcodeList.cpp : 定义控制台应用程序的入口点。vs2013 测试通过 2 // 3 4 #include "stdafx.h" 5 #include <Windows.h> 6 #include <iostream> 7 8 using namespace std; 9 10 struct ListNode 11 { 12 int val; 13 ListNode *next; 14 ListNode(int x) : val(x), next(nullptr){}; 15 }; 16 17 void showList(ListNode *Head) { 18 ListNode *p = Head; 19 while (p != nullptr) { 20 cout << p->val << '\t'; 21 p = p->next; 22 } 23 cout << endl; 24 } 25 26 ListNode* createList(int n) { 27 ListNode dummy(-1); 28 ListNode *prev = &dummy; 29 for (int i = 0; i < n; ++i) { 30 int value; 31 cout << "input number:"; 32 cin >> value; 33 prev->next = new ListNode(value); 34 prev = prev->next; 35 } 36 return dummy.next; 37 } 38 39 ListNode* addTwoNumbers(ListNode *l1, ListNode *l2) { 40 ListNode *pa = l1; 41 ListNode *pb = l2; 42 ListNode dummy(-1); // 头节点,目的是只有一个元素的时候不需要特殊考虑 43 ListNode *prev = &dummy; 44 int carry = 0; // 表示进位 45 while (pa != nullptr || pb != nullptr) { 46 const int ai = (pa == nullptr ? 0 : pa->val); 47 const int bi = (pb == nullptr ? 0 : pb->val); 48 const int value = (ai + bi + carry) % 10; 49 carry = (ai + bi + carry) / 10; 50 prev->next = new ListNode(value); 51 52 pa = pa->next; 53 pb = pb->next; 54 prev = prev->next; 55 } 56 if (carry > 0) 57 prev->next = new ListNode(carry); 58 return dummy.next; 59 } 60 61 62 int _tmain(int argc, _TCHAR* argv[]) 63 { 64 ListNode *l1 = createList(3); 65 showList(l1); 66 ListNode *l2 = createList(3); 67 showList(l2); 68 ListNode *result = addTwoNumbers(l1, l2); 69 showList(result); 70 system("pause"); 71 return 0; 72 }
1, addTwoNumbers (思路同 数组题总结中的 plusOne 相似)
1 ListNode* addTwoNumbers(ListNode *l1, ListNode *l2) { 2 ListNode *pa = l1; 3 ListNode *pb = l2; 4 ListNode dummy(-1); // 头节点,目的是只有一个元素的时候不需要特殊考虑 5 ListNode *prev = &dummy; 6 int carry = 0; // 表示进位 7 while (pa != nullptr || pb != nullptr) { 8 const int ai = (pa == nullptr ? 0 : pa->val); 9 const int bi = (pb == nullptr ? 0 : pb->val); 10 const int value = (ai + bi + carry) % 10; 11 carry = (ai + bi + carry) / 10; 12 prev->next = new ListNode(value); 13 14 pa = pa->next; 15 pb = pb->next; 16 prev = prev->next; 17 } 18 if (carry > 0) 19 prev->next = new ListNode(carry); 20 return dummy.next; 21 }
2,reverseBetween
1 ListNode* reverseBetween(ListNode *head, int m, int n) { 2 ListNode dummy(-1); 3 dummy.next = head; 4 5 ListNode *prev = &dummy; 6 for(int i = 0; i < m-1; ++i) { 7 prev = prev->next; // prev 指向第 m 个位置之前的元素 8 } 9 ListNode * head2 = prev; 10 11 prev = head2->next; 12 ListNode *cur = prev->next; // cur 指向要执行头插操作的节点 13 for (int i = m; i < n; ++i) { // 头插的元素个数为 n-m 个 14 prev->next = cur->next; 15 cur->next = head->next; // 头插法,从要反转位置的下一个元素进行头插 16 head->next = cur; 17 18 cur = prev->next; 19 } 20 return dummy.next; 21 }
3,partition List
1 ListNode* partition1(ListNode* head, int x) { // *******这个方法特别好用******* 2 ListNode left_dummy(-1); // 定义小于3 的链表头节点 3 ListNode right_dummy(-1); // 定义大于等于3 的链表头节点 4 5 auto left_cur = &left_dummy; 6 auto right_cur = &right_dummy; 7 8 for (ListNode *cur = head; cur != nullptr; cur = cur->next) { 9 if (cur->val < x) { 10 left_cur->next = cur; 11 left_cur = cur; 12 } 13 else 14 { 15 right_cur->next = cur; 16 right_cur = cur; 17 } 18 } 19 left_cur->next = right_dummy.next; 20 right_cur->next = nullptr; 21 22 return left_dummy.next; 23 } 24 25 26 ListNode* partition2(ListNode *head, int x) { 27 if (head == nullptr) return head; 28 ListNode dummy(-1); 29 dummy.next = head; 30 31 ListNode *prev = &dummy; 32 for (ListNode *curr = head; curr->next != nullptr; curr = curr->next) { //对每一个元素进行判断,是否需要类头插 33 while (curr->next != nullptr) 34 { 35 if (curr->val < x) 36 { 37 prev = curr; // prev 始终指向最后一个小于 3 的节点,在此之后插入值小于 3 的节点 38 curr = curr->next; 39 } 40 else 41 { 42 break;; 43 } 44 } 45 ListNode *prev_last = curr; // 找到下一个要头插的节点 46 ListNode *last = curr->next; 47 while (last->next != nullptr) 48 { 49 if (last->val >= 3) { 50 prev_last = last; 51 last = last->next; 52 } 53 else 54 { 55 break; 56 } 57 } 58 prev_last->next = last->next; // 在最后一个小于 3 的元素之后插入 59 last->next = prev->next; 60 prev->next = last; // 每次交换之后 curr 是指向最后一个大于等于 3 的节点,在此之前插入后面小于 3 的节点 61 } 62 return dummy.next; 63 }
4, deleteDuplicates(I)
1 // ***********方法1********************* 2 ListNode* deleteDuplicates1(ListNode *head) { 3 if (head == nullptr) return head; 4 ListNode dummy(head->val + 1); // 保证不和 head->val 相同即可 5 dummy.next = head; 6 7 ListNode *prev = &dummy; 8 while (head != nullptr) // head 指向后一个值,只要 head 有值,就要进行比较 9 { 10 if (prev->val == head->val) { 11 prev->next = head->next; 12 delete head; // 注意内存泄漏,删除的节点要释放内存,temp 指向要删除的节点 13 head = prev->next; // 此时 head 为一个野指针,可以重新赋值 14 15 } 16 else { 17 prev = head; 18 head = head->next; 19 } 20 } 21 return dummy.next; 22 } 23 24 // ***********方法2********************* 25 void recur(ListNode *prev, ListNode *cur) { 26 if (cur == nullptr) return; 27 28 if (prev->val == cur->val) { 29 prev->next = cur->next; 30 delete cur; 31 recur(prev, prev->next); 32 } 33 else { 34 recur(prev->next, cur->next); 35 } 36 } 37 ListNode* deleteDuplicates2(ListNode *head) { // 递归版本 38 if (!head) return head; 39 ListNode dummy(head->val + 1); // 理由同上 40 dummy.next = head; 41 42 recur(&dummy, head); // 前一个和后一个 43 return dummy.next; 44 } 45 46 // ***********方法3********************* 47 ListNode* deleteDuplicates3(ListNode *head){ // 迭代版本,基本思想和 deleteDuplicates1 一样 48 if (head == nullptr) return nullptr; 49 50 for (ListNode *prev = head, *curr = head->next; curr != nullptr; curr = prev->next) { 51 if (prev->val == curr->val) { 52 prev->next = curr->next; 53 delete curr; // 删除了 curr,系统并不会把 curr 设为空指针,而是还指向原来已经释放空间的内存地址 54 } 55 else { 56 prev = curr; 57 } 58 } 59 return head; 60 }
deleteDuplicates(II)
1 ListNode* deleteDuplicatesII1(ListNode *head) { // 迭代版本 2 if (head == nullptr) return head; 3 ListNode dummy(-1); 4 // dummy.next = head; 5 6 ListNode *prev = &dummy; 7 ListNode *curr = head; 8 while (curr != nullptr) 9 { 10 bool duplicated = false; 11 while (curr->next != nullptr && curr->val == curr->next->val) { 12 duplicated = true; 13 ListNode *temp = curr; 14 curr = curr->next; 15 delete temp; 16 } 17 if (duplicated) { // 已经有重复元素,需要删除重复元素的最后一个元素 18 ListNode *temp = curr; 19 curr = curr->next; 20 delete temp; 21 continue; // 继续检查下一个元素,重新回到起点判断。 22 } 23 prev->next = curr; 24 prev = prev->next; 25 curr = curr->next; 26 } 27 prev->next = curr; 28 return dummy.next; 29 } 30 31 ListNode* deleteDuplicatesII2(ListNode *head) { // 递归版本 32 if (!head || head->next) return head; 33 34 ListNode *p = head->next; 35 if (head->val == p->val) { 36 while (p && head->val == p->val) { 37 ListNode *tmp = p; 38 p = p->next; 39 delete tmp; 40 } 41 delete head; 42 return deleteDuplicatesII2(p); 43 } 44 else { 45 head->next = deleteDuplicatesII2(head->next); 46 return head; 47 } 48 }
5, rotate List
1 ListNode* rotateRight(ListNode *head, int k) { 2 if (head == nullptr || k == 0) return head; 3 4 int len = 1; 5 ListNode *p = head; 6 while (p->next != nullptr) { // 求链表长度 7 ++len; 8 p = p->next; 9 } 10 k = len - k % len; 11 p->next = head; 12 for (int i = 1; i < k; ++i) { // head 向后移动 k-1 步 | p 向右移动 k 步 13 head = head->next; 14 } 15 p = head; // 重新使用 p 指针 16 head = head->next; 17 p->next = nullptr; 18 return head; 19 }
6, remove Nth Node From End of List
1 ListNode* removeNthFromEnd(ListNode *head, int n) { 2 if (head == nullptr) return head; 3 ListNode dummy(-1); 4 dummy.next = head; 5 ListNode *first = &dummy; 6 ListNode *last = &dummy; 7 for (int i = 0; i < n; ++i) { // 利用前后指针 8 last = last->next; 9 } 10 while (last->next != nullptr) { 11 first = first->next; 12 last = last->next; 13 } 14 ListNode *temp = first->next; 15 first->next = first->next->next; 16 delete temp; 17 return dummy.next; 18 }
7, Swap Nodes in Pairs
1 ListNode* swapPairs1(ListNode *head) { 2 if (!head || !head->next) return head; 3 ListNode *p = head; 4 ListNode dummy(-1); 5 dummy.next = head->next; // 直接指向新的头节点 6 ListNode *prev = &dummy; 7 8 while (p && p->next) { 9 prev->next = p->next; 10 ListNode *temp = p->next->next; 11 p->next->next = p; 12 p->next = temp; 13 prev = p; 14 p = temp; 15 } 16 return dummy.next; 17 } 18 19 ListNode* swapPairs2(ListNode *head) { 20 ListNode* p = head; 21 while (p && p->next) { 22 swap(p->val, p->next->val); 23 p = p->next->next; 24 } 25 return head; 26 }
8, Reverse Nodes in k-Group
1 ListNode* reverseKGroup(ListNode *head, int k) { 2 if (!head ||!head->next || k <= 1) return head; 3 ListNode dummy(-1); 4 dummy.next = head; 5 ListNode *prev = &dummy; 6 bool enough = true; 7 8 while (true) { 9 ListNode *p = head; 10 ListNode *begin = head; 11 for (int i = 0; i < k; ++i) { 12 if (p) p = p->next; 13 else { 14 enough = false; 15 prev->next = begin; // 把最后不够反转的节点连接起来 16 return dummy.next; 17 } 18 } 19 ListNode *prev_next = begin; 20 if (enough) { 21 for (int i = 0; i < k; ++i) { // 头插法 22 ListNode* temp = begin->next; 23 if (i == 0) begin->next = nullptr; // 如果是最后一个节点,就把该节点的 next 置为 nullptr ,为了 showList 函数能展示 24 else begin->next = prev->next; 25 prev->next = begin; 26 begin = temp; 27 } 28 } 29 // showList(dummy.next); // using test 30 prev = prev_next; 31 head = begin; 32 }// while 33 }
9, Linked List Cycle
1 bool hasCycle1(ListNode *head) { // STL::unordered_map 2 unordered_map<ListNode*, bool> visted; // 检测节点地址是否重复访问 3 for (head; head != nullptr; head = head->next) { 4 if (visted.find(head) != visted.end()) { 5 visted.find(head)->second = true; // 有没有都可以 6 return false; 7 } 8 else { 9 visted.find(head)->second = false; 10 } 11 } 12 return true; 13 } 14 15 bool hasCycle2(ListNode *head) { 16 ListNode *slow = head; 17 ListNode *fast = head; 18 while (fast && fast->next) { 19 slow = slow->next; // slow 每次走一步 20 fast = fast->next->next; // fast 每次走两步,看作 fast 追 slow 的话,每次距离缩短 1 ,不会跳过slow的 21 if (slow == fast) 22 return true; 23 } 24 return false; 25 }
Linked List Cycle(II)
1 ListNode* detectCycle1(ListNode *head) { // STL::unordered_map 2 unordered_map<ListNode*, bool> visted; 3 for (head; head != nullptr; head = head->next) { 4 if (visted.find(head) != visted.end()) { 5 return head; 6 } 7 else { 8 visted.find(head)->second = false; 9 } 10 } 11 return nullptr; 12 } 13 14 ListNode* detectCycle2(ListNode *head) { 15 ListNode* slow = head; 16 ListNode* fast = head; 17 18 while (fast && fast->next) { 19 slow = slow->next; 20 fast = fast->next->next; 21 if (slow == fast) { 22 ListNode *p = head; 23 while (p != slow) { // 思路来源:https://blog.csdn.net/xy010902100449/article/details/48995255 24 slow = slow->next; 25 p = p->next; 26 } 27 return p; 28 } 29 } 30 return nullptr; 31 }
10, Reorder List
1 ListNode* reverse(ListNode *head) { 2 if (!head || !head->next) return head; 3 ListNode dummy(-1); 4 dummy.next = head; 5 6 ListNode *prev = &dummy; 7 ListNode *curr = head; 8 while (curr) { 9 ListNode* temp = curr->next; // 保存下一个节点 10 if (curr == head) curr->next = nullptr; // 头插法 11 else curr->next = prev->next; 12 prev->next = curr; 13 curr = temp; 14 } 15 return dummy.next; 16 } 17 18 ListNode* mergeList(ListNode *list1, ListNode *list2) { // 把 list2 合并到 list1 中 19 if (!list1) return list2; 20 if (!list2) return list1; 21 22 ListNode *curr1 = list1; 23 ListNode *curr2 = list2; 24 ListNode *temp1 = nullptr; 25 ListNode *temp2 = nullptr; 26 while (curr1->next && curr2->next) { 27 temp1 = curr1->next; 28 temp2 = curr2->next; 29 curr2->next = curr1->next; 30 curr1->next = curr2; 31 curr1 = temp1; 32 curr2 = temp2; 33 } 34 if (!curr1->next) // 如果第一个链表节点少,需要把长的链表后面的节点链接上,如果第二个少,不需要做处理 35 curr1->next = temp2; 36 return list1; 37 } 38 39 ListNode* reorderList(ListNode *head) { // 先反转后半部分链表,然后再交互合并两个链表 40 if (!head || !head->next) return head; 41 42 ListNode *slow = head; 43 ListNode *fast = head; 44 ListNode *prev = nullptr; 45 46 while (fast && fast->next) { 47 prev = slow; // prev 后面断开,slow 指向后半链表的第一个节点 48 slow = slow->next; 49 fast = fast->next->next; 50 } 51 prev->next = nullptr; 52 ListNode *head2 = reverse(slow); 53 54 // merge two lists head && head2 55 head = mergeList(head, head2); // 把 head2 合并到 head 中 56 return head; 57 }
11, LRU Cache
1 class LRUCache { 2 private: 3 struct CacheNode { 4 int key; 5 int value; 6 CacheNode(int k, int v) : key(k), value(v) {}; 7 }; 8 public: 9 LRUCache(int capacity) { 10 this->capacity = capacity; 11 } 12 int get(int key) { 13 if (cacheMap.find(key) == cacheMap.end()) return -1; 14 15 cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]); // 移动最新访问的节点到最前面 16 cacheMap[key] = cacheList.begin(); // 更新 map 中节点的地址 17 return cacheMap[key]->value; 18 } 19 void set(int key, int value) { 20 if (cacheMap.find(key) == cacheMap.end()) { // 没有该元素 21 if (cacheList.size() == capacity) { // 空间已满 22 cacheMap.erase(cacheList.back().key); 23 cacheList.pop_back(); 24 } 25 // 空间不满,插入新节点到链表头部 26 cacheList.push_front(CacheNode(key, value)); 27 cacheMap[key] = cacheList.begin(); 28 } 29 else { // 存在该元素,更新节点值,并把该节点放到链表头部,更新 cacheMap 中的值 30 cacheMap[key]->key = value; 31 cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]); 32 cacheMap[key] = cacheList.begin(); 33 } 34 } 35 private: 36 list<CacheNode> cacheList; 37 unordered_map<int, list<CacheNode>::iterator> cacheMap; 38 int capacity; 39 };
12, deep Copy
1 RandomListNode* copyRandomList1(RandomListNode *head) { // STL::unordered_map 2 if (head == nullptr) return nullptr; 3 4 RandomListNode dummy(-1); 5 RandomListNode *scan = &dummy; 6 RandomListNode *curr = head; 7 unordered_map<RandomListNode*, RandomListNode*> mapping; 8 9 while (curr != nullptr) { 10 scan->next = new RandomListNode(curr->label); 11 mapping.insert(curr, scan->next); // 存储 原链表节点和复制链表节点的对应关系 12 curr = curr->next; 13 scan = scan->next; 14 } 15 curr = head; 16 scan = &dummy; 17 while (curr != nullptr) { // 赋值各个节点的 random 域 18 scan->next->random = mapping[curr->random]; 19 curr = curr->next; 20 scan = scan->next; 21 } 22 return dummy.next; 23 } 24 25 RandomListNode* copyRandomList2(RandomListNode *head) { 26 if (head == nullptr) return head; 27 28 RandomListNode *scan = head; 29 while (!scan) { // step1: 第一遍扫描,对每个节点赋值 30 RandomListNode *newNode = new RandomListNode(scan->label); 31 newNode->next = scan->next; 32 scan->next = newNode; 33 scan = newNode->next; 34 } 35 scan = head; // step2: 第2遍扫描,对每个复制节点的 random 域进行赋值 36 while (!scan) { 37 if (!scan->random) { 38 scan->next->random = scan->random->next; // 把前面复制节点的 random 指向后面复制节点的 random 39 } 40 } 41 RandomListNode *newHead = head->next; 42 scan = head; // step3:第3遍扫描,拆分奇偶节点,分成两个链表,奇数组成的链表为原链表,偶数组成的链表为复制链表 43 while (!scan) { 44 RandomListNode *evenNode = scan->next; 45 scan->next = evenNode->next; 46 if (scan->next != nullptr) { 47 evenNode->next = scan->next->next; 48 } 49 scan = scan->next; 50 } 51 return newHead; 52 }
以上题目来源于:https://github.com/soulmachine/leetcode(leetcode-cpp.pdf)
所有博文均为原著,如若转载,请注明出处!