20210308 & 20210309: A collection of linked list questions

Review of linked list topics

Write in front

  1. The last time this category of topics was written was exactly 6 months ago, that is, my two blogs 20200908 and 20200909 involved all the topics in this article today, which are all linked list related. The small goal of this month is to merge and rewrite the categories of Likou's topics before the end. Aiming to improve the overall level of architecture, self-evaluation is that I have become more proficient and systematically mastered cpp this year. Although my personal direction is SDR, the exercises on thinking like algorithms are still not available. Future development will be hardware or software. Or simulation is inseparable from these basic capabilities. That's all the nonsense, everyone encourages!

topic

    1. Reverse linked list
      Insert picture description here
    1. Reverse Linked List II
      Insert picture description here
    1. Circular Linked List II
      Insert picture description here
    1. Split list
      Insert picture description here
    1. Copy a linked list with random pointers
      Insert picture description here
    1. Combine K ascending linked lists
      Insert picture description here

Ideas and algorithms

    1. Reverse linked list
    1. Reverse Linked List II
    1. Circular Linked List II
    1. Split list
    1. Copy a linked list with random pointers
    1. Combine K ascending linked lists

The above topics should be considered as covering most of the main points of the linked list. Skilled writing and mastering of ideas can basically do this kind of topics with ease.

Code

  1. Reverse linked list
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    ListNode* reverseList(ListNode* head) {
    
    
        ListNode* new_head = NULL;
        while (head) {
    
    
            // 备份head->next
            ListNode* tmp = head->next;
            // 更新head->next
            head->next = new_head;
            // 移动head_next
            new_head = head;
            // 遍历链表
            head = tmp;
        }
        return new_head;
    }
};
  1. Reverse Linked List II
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
    
    
        int change_len = n - m + 1;
        ListNode* pre_head = NULL;
        ListNode* result = head;
        // 将head向前移动m-1次找到中间段 翻转之前的head,
        while (head && --m) {
    
    
            pre_head = head;
            head = head->next;
        }
        // 这个head就是翻转之后的中间段的tail,这里直接给好
        ListNode* tail = head;

        ListNode* new_head = NULL;
        // m-n段的翻转操作
        while (head && change_len) {
    
    
            // 备份即将被翻转的head的下一跳
            ListNode* next = head->next;
            // 重新指定下一跳为新的new_head
            head->next = new_head;
            // head和new_head更新
            new_head = head;
            head = next;
            // 最后要翻转n-m+1次。
            --change_len;
        }
        // 最后连接子段和原来的pre_head以及尾巴,注意此时的尾巴就是head
        tail->next = head;
        if (pre_head) {
    
    
            pre_head->next = new_head;
        } else {
    
    
            // 注意如果pre_head为NULL,那么结果直接返回new_head,即若是从第一个位置开始翻转,那么头节点不能为空。
            result = new_head;
        }
        return result;
    }
};
    1. Circular Linked List II
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        std::set<ListNode*> node_set;
        while(head) {
    
    
            if(node_set.find(head) != node_set.end()) {
    
    
                return head;
            }
            node_set.insert(head);
            head = head->next;
        }
        return NULL;
    }
};
    1. Split list
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    ListNode* partition(ListNode* head, int x) {
    
    
        // 初始化两个临时头结点和两个临时指针
        ListNode less_head;
        ListNode more_head;
        ListNode* less_ptr = &less_head;
        ListNode* more_ptr = &more_head;
        // 遍历,将链表的数据分类跟在more_head和less_head之后
        while (head) {
    
    
            if (head->val >= x) {
    
    
                more_ptr->next = head;
                more_ptr = head;
            } else {
    
    
                less_ptr->next = head;
                less_ptr = head;
            }
            head = head->next;
        }
        // 连接即可
        less_ptr->next = more_head.next;
        more_ptr->next = NULL;
        // 注意返回不要搞错了,返回的是less_head.next
        return less_head.next;
    }
};
    1. Copy a linked list with random pointers
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
    
    
public:
    Node* copyRandomList(Node* head) {
    
    
        map<Node*,int> node_map;
        vector<Node*> node_vec;
        Node* ptr = head;
        // 遍历,用map将对应的id存起来,用vec将对应的节点存下来
        int i = 0;
        while (ptr) {
    
    
            node_vec.push_back(new Node(ptr->val));
            node_map[ptr] = i;
            ptr = ptr->next;
            ++i;
        }
        node_vec.push_back(0);
        // 再次遍历链表并进行连接next和random指针域
        ptr = head;
        i = 0;
        while (ptr) {
    
    
            // 连接next域
            node_vec[i]->next = node_vec[i + 1];
            // 连接random域
            if (ptr->random) {
    
    
                int id = node_map[ptr->random];
                node_vec[i]->random = node_vec[id];
            }
            ptr = ptr->next;
            ++i;
        }
        return node_vec[0];
     }
};
    1. Combine K ascending linked lists
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    
    
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
    
    
        if (lists.size() == 0) {
    
    
            return NULL;
        }
        if (lists.size() == 1) {
    
    
            return lists[0];
        }
        if (lists.size() == 2) {
    
    
            return mergeTwoLists(lists[0],lists[1]);
        }
        int mid = lists.size() / 2;
        vector<ListNode*> subList1;
        vector<ListNode*> subList2;
        for (int i = 0; i < mid; ++i) {
    
    
            subList1.push_back(lists[i]);
        }
        for (int i = mid; i < lists.size(); ++i) {
    
    
            subList2.push_back(lists[i]);
        }

        ListNode* l1 = mergeKLists(subList1);
        ListNode* l2 = mergeKLists(subList2);
        return mergeTwoLists(l1,l2);

    }

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    
    
        ListNode tmp_head(0);
        ListNode* pre = &tmp_head;
        while (l1 && l2) {
    
    
            if (l1->val < l2->val) {
    
    
                pre->next = l1;
                l1 = l1->next;
            } else {
    
    
                pre->next = l2;
                l2 = l2->next;
            }
            pre = pre->next;
        }
        if (l1) {
    
    
            pre->next = l1;
        }
        if (l2) {
    
    
            pre->next = l2;
        }
        return tmp_head.next;
    }
};

Guess you like

Origin blog.csdn.net/qq_36828395/article/details/114608255