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

 

posted on 2019-02-21 16:50  爱笑的张飞  阅读(290)  评论(0编辑  收藏  举报

导航