zoukankan      html  css  js  c++  java
  • 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 << '	';
    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 }
    listTestFrame

    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 }
    addTwoNumbers

     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 }
    reverseBetween

     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 }
    partition

     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

         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 }
    deleteDuplicates

     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 }
    rotateRight

     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 }
    removeNthFromEnd

     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 }
    swapPairs

     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 }
    reverseKGroup

     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 }
    hasCycle

          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 }
    detectCycle

     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 }
    reorderList

     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 };
    LRU Cache

     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 }
    copyRandomList

    以上题目来源于:https://github.com/soulmachine/leetcode(leetcode-cpp.pdf)

    所有博文均为原著,如若转载,请注明出处!
  • 相关阅读:
    java中VO、PO、DTO 、DO、POJO、BO、TO
    java可变参数
    排序
    快速排序
    单元测试概述
    Spring 对事务管理的支持
    Spring的事务管理基础知识
    混合切面类型
    基于Schema配置切面
    Spring AOP @AspectJ进阶
  • 原文地址:https://www.cnblogs.com/zpcoding/p/10413637.html
Copyright © 2011-2022 走看看