1. 程式人生 > 實用技巧 >連結基礎 連結串列常考的題目

連結基礎 連結串列常考的題目

連結串列的常考題目

1.1反轉連結串列

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode * new_head = nullptr;
        while
(head) { ListNode* next = head->next; head->next = new_head; new_head = head; head = next; } return new_head; } };

1.2反轉連結串列 II

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 
*/ class Solution { public: ListNode* reverseBetween(ListNode* head, int m, int n) { int change_len = n-m+1; ListNode *pre_head = nullptr; ListNode *result = head; while(head && --m) { pre_head = head; head = head->next; } ListNode
* tail = head; ListNode* new_head = nullptr; while(head && change_len) { ListNode * next = head->next; head->next = new_head; new_head = head; head = next; change_len--; } tail->next = head; if(pre_head!=nullptr) { pre_head->next = new_head; } else { result = new_head; } return result; } };

2相交連結串列

方法一:利用雜湊表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_set<ListNode*> s;
        while(headB)
        {
            s.insert(headB);
            headB = headB->next;
        }

        while(headA)
        {
            if(s.count(headA))
                return headA;
            headA = headA->next;
        }
        return nullptr;
    }
};

方法二:雙指標

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
int get_list_length(ListNode *head)
{
    int len = 0;
    while(head)
    {
        len++;
        head = head->next;
    }
    return len;
}
ListNode * movehead(int longlen, int shortlen, ListNode* head)
{
    int dif = longlen-shortlen;
    while(dif)
    {
        head = head->next;
        dif--;
    }
    return head;
}
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int la = get_list_length(headA);
        int lb = get_list_length(headB);
        if (la>lb){
            headA = movehead(la,lb,headA);
        }
        else
        {
            headB = movehead(lb,la,headB);
        }
        while(headA && headB)
        {
            if(headA==headB)
            {
                return headA;
            }
            headA = headA->next;
            headB = headB->next;
        }
        return nullptr;
    }
};

3環形連結串列

方法一:利用set

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        set<ListNode*>s;
        while(head)
        {
            if (s.count(head))
                return true;
            s.insert(head);
            head = head->next;
        }
        return false;
    }
};

方法二:快慢指標

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==nullptr || head->next == nullptr)
            return false;
        ListNode *slow = head;
        ListNode *fast = head->next;
        while(slow != fast)
        {
            if (fast==nullptr || fast->next==nullptr)
                return false;
            slow = slow->next;
            fast = fast->next->next;
        }
        return true;
    }
};

3環形連結串列 II

方法一:利用set

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode *> st;
        while(head!=NULL){
            if(st.count(head)) return head;
            st.insert(head);
            head=head->next;
        }
        return NULL;
    }
};

方法二:快慢指標

/**
 * 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) {
        ListNode *fast = head, *slow = head;

        while (fast and fast->next) { //寫的時候注意 fast == slow 不要寫在這兒,因為剛開始走的時候兩個都是 head
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) {
                break;
            }
        }

        if (fast == NULL || fast->next == NULL) {
            return NULL;
        }

        ListNode *offset = head;
        while (offset != fast) {
            offset = offset->next;
            fast = fast->next;
        }
        return offset;
    }
};

4分隔連結串列

方法:利用臨時頭結點

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode lesshead(0);
        ListNode morehead(0);
        ListNode *less = &lesshead;
        ListNode *more = &morehead;

        while(head)
        {
            if (head->val < x)
            {
                less->next = head;
                less = less->next;
            }
            else
            {
                more->next = head;
                more = more->next;
            }
            head = head->next;
        }
        less->next = morehead.next;
        more->next= nullptr;
        return lesshead.next;
    }
};

5複製帶隨機指標的連結串列

方法一:利用一個雜湊表,儲存一個地址到節點位置的map

/*
// 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;
        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);
        ptr = head;
        i = 0;
        while(ptr)
        {
            node_vec[i]->next = node_vec[i+1];
            if(ptr->random)
            {
                int id = node_map[ptr->random];
                node_vec[i]->random = node_vec[id];
            }
            ptr = ptr->next;
            i++;
        }
        return node_vec[0];
    }
};

方法二:不使用輔助空間的情況下實現O(N)的時間效率

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

void colneNodes(Node* head)
{
    Node* ptr = head;
    while(ptr)
    {
        Node* pclone = new Node(ptr->val);
        pclone->next = ptr->next;
        pclone->random = nullptr;
        ptr->next = pclone;
        ptr = pclone->next;
    }
}

void connectRandom(Node* head)
{
    Node *ptr = head;
    while(ptr)
    {
        Node * pclone = ptr->next;
        if (ptr->random != nullptr)
        {
            pclone->random = ptr->random->next;
        }
        ptr = pclone->next;
    }
}

Node* Reconnect(Node* head) 
{
    Node *ptr = head;
    Node *pcloneHead = nullptr;
    Node *pcloneNode = nullptr;

    if (ptr)
    {
        pcloneHead = pcloneNode = ptr->next;
        ptr->next = pcloneNode->next;
        ptr = ptr->next;
    }
    while(ptr)
    {
        pcloneNode->next = ptr->next;
        pcloneNode = pcloneNode->next;
        ptr->next = pcloneNode->next;
        ptr = ptr->next;
    }
    return pcloneHead;
}
 
class Solution {
public:
    Node* copyRandomList(Node* head) {
       colneNodes(head);
       connectRandom(head);
       return Reconnect(head);
    }
};

6.1合併兩個有序連結串列

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */


class Solution {
public:
    ListNode* mergeTwoList(ListNode *a, ListNode *b)
    {
        if (a == nullptr || b == nullptr)
            return a ? a : b;
        
        ListNode *ptr
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        vector<ListNode *> v;
        for (int i=0;i<lists.size();i++)
        {
            ListNode* head = lists[i];
            while(head)
            {
                v.push_back(head);
                head = head->next;
            }
        }
        if(v.size()==0)
            return nullptr;
        
        sort(v.begin(),v.end(),cmp);
        for (int i=1;i<v.size();i++)
        {
            v[i-1]->next = v[i];
        }
        v[v.size()-1]->next = nullptr;
        return v[0];
    }
};

6.2合併K個排序連結串列

方法一:排序後相連

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

bool cmp(const ListNode* a, const ListNode* b)
{
    return a->val < b->val;
}
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        vector<ListNode *> v;
        for (int i=0;i<lists.size();i++)
        {
            ListNode* head = lists[i];
            while(head)
            {
                v.push_back(head);
                head = head->next;
            }
        }
        if(v.size()==0)
            return nullptr;
        
        sort(v.begin(),v.end(),cmp);
        for (int i=1;i<v.size();i++)
        {
            v[i-1]->next = v[i];
        }
        v[v.size()-1]->next = nullptr;
        return v[0];
    }
};

方法二:分治後相連

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */


class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1==nullptr)
            return l2;
        if (l2==nullptr)
            return l1;
        ListNode * first = new ListNode(0);
        ListNode * head = first;
        while (l1 != nullptr && l2 != nullptr)
        {
            if(l1->val <l2->val)
            {
                first->next = l1;
                l1 = l1->next;
            }
            else
            {
                first->next = l2;
                l2 = l2->next;
            }
            first = first->next;
        }
        first->next = l1 == nullptr ? l2 : l1;
        
        return head->next;
    }

    ListNode* merge(vector<ListNode*>& lists, int l, int r)
    {
        if (l==r)
            return lists[l];
        if(l>r)
            return nullptr;
        int mid = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists, 0, lists.size() - 1);
    }
};