LeetCode 【数据结构与算法专栏】【链表】

链表leetcode专栏

leetcode 23 合并K个升序链表(采用小根堆来拿k个Node中的MinNode)

//采用构建最小堆来拿到每次K个链表结点中的最小值的那个结点
//时间复杂度O(NlogK)
class Solution {
public:
    struct cmp {
        bool operator() (ListNode* l1, ListNode* l2) {     
            return l1->val > l2->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, cmp> pq;
        for (int i = 0; i < lists.size(); i++) {
            if (lists[i] != NULL) {
                pq.push(lists[i]);
            }
        }
        ListNode* dummyNode = new ListNode();
        ListNode* cur = dummyNode;
        while (!pq.empty()) {
            ListNode* p = pq.top();
            pq.pop();
            if (p->next != NULL) {
                pq.push(p->next);
            }
            cur->next = p;
            cur = p;
        }
        return dummyNode->next;
    }
};

leetcode 23 合并K个升序链表(递归分治思想+合并2个升序链表算法)

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* p, ListNode* q) {     //合并两个链表的算法
        ListNode* dummyNode = new ListNode();
        ListNode* cur = dummyNode;
        while (p != NULL && q != NULL) {
            if (p->val <= q->val) {
                cur->next = p;
                p = p->next;
            }
            else {
                cur->next = q;
                q = q->next;
            }
            cur = cur->next;
        }
        if (p != NULL) {
            cur->next = p;
        }
        if (q != NULL) {
            cur->next = q;
        }
        return dummyNode->next;
    }
    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*> lists1;
        vector<ListNode*> lists2;
        for (int i = 0; i < mid; i++) {
            lists1.push_back(lists[i]);
        }
        for (int i = mid; i < lists.size(); i++) {
            lists2.push_back(lists[i]);
        }
        ListNode* p1 = mergeKLists(lists1);
        ListNode* p2 = mergeKLists(lists2);
        return mergeTwoLists(p1, p2);
    }
};

leetcode 203 移除链表元素

/**
 * 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* removeElements(ListNode* head, int val) {
        ListNode* dummyNode = new ListNode();
        dummyNode->next = head;
        ListNode* cur = head;
        ListNode* pre = dummyNode;
        while (cur != nullptr) {
            if (cur->val == val) {
                ListNode* tmp = cur;
                pre->next = cur->next;
                cur = cur->next;
                delete tmp;
            }
            else {
                pre = cur;
                cur = cur->next;                
            }
        }
        return dummyNode->next;
    }
};

leetcode 707 设计链表

设计链表问题主要在于虚拟头结点的使用,和题目中所给的index的要求,index是从0开始的

class MyLinkedList {
public:
    struct LinkNode {
        int val;
        LinkNode* next;
        LinkNode(int x) : val(x), next(nullptr) {}
    };

    MyLinkedList() {
        _dummyNode = new LinkNode(0);
        _size = 0;
    }
    
    int get(int index) {
        if (index >= _size) {
            return -1;
        }
        LinkNode* cur = _dummyNode;
        while (index != -1) {
            cur = cur->next;
            index--;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkNode* tmp = new LinkNode(val);
        tmp->next = _dummyNode->next;
        _dummyNode->next = tmp;
        _size++;
    }
    
    void addAtTail(int val) {
        LinkNode* tmp = new LinkNode(val);
        LinkNode* cur = _dummyNode;
        while (cur->next != nullptr) {
            cur = cur->next;
        }
        cur->next = tmp;
        _size++;
    }
    
    void addAtIndex(int index, int val) {
        LinkNode* tmp = new LinkNode(val);
        if (index > _size) {
            return;
        }
        else if (index < 0) {
            tmp->next = _dummyNode->next;
            _dummyNode->next = tmp;
        }
        else if (index == _size) {
            LinkNode* cur = _dummyNode;
            while (cur->next != nullptr) {
                cur = cur->next;
            }
            cur->next = tmp;
        }
        else {
            LinkNode* pre = _dummyNode;
            LinkNode* cur = _dummyNode;
            while (index != -1) {
                pre = cur;
                cur = cur->next;
                index--;
            }
            tmp->next = pre->next;
            pre->next = tmp;
        }
        _size++;
    }
    
    void deleteAtIndex(int index) {
        if (index >= _size || index < 0) {
            return;
        }
        LinkNode* pre = _dummyNode;
        LinkNode* cur = _dummyNode;
        while (index != -1) {
            pre = cur;
            cur = cur->next;
            index--;
        }
        LinkNode* tmp = cur;
        pre->next = cur->next;
        delete tmp;
        _size--;
    }
private:
    LinkNode* _dummyNode;
    int _size;
};

leetcode 206 翻转链表

采用三个指针

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = nullptr;
        ListNode* cur = head;
        ListNode* after = nullptr;
        
        while (cur != nullptr) {
            after = cur->next;
            cur->next = pre;
            pre = cur;
            cur = after;
        }
        return pre;
    }
};

采用递归方法

class Solution {
public:
    ListNode* reverseList(ListNode* head) { 
        // ListNode* cur = head;
        // ListNode* pre = NULL;
        return reverse(nullptr, head);
    }
    ListNode* reverse(ListNode* pre, ListNode* cur) {
        if (cur == nullptr) {
            return pre;
        }
        ListNode* after = cur->next;
        cur->next = pre;
        // pre = cur;
        // cur = after;
        return reverse(cur, after);
    }
};

错误写法,reverse中传入cur->next之前,它的值已经被pre覆盖了

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        return reverse(NULL, head);
    }
    ListNode* reverse(ListNode* pre, ListNode* cur) {
        if (cur == NULL) {
            return pre;
        }
        //ListNode* aft = cur->next;
        cur->next = pre;
        return reverse(cur, cur->next);
    }
};

leetcode 92 翻转链表II

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = nullptr;
        ListNode* cur = head;
        ListNode* after = nullptr;
        
        while (cur != nullptr) {
            after = cur->next;
            cur->next = pre;
            pre = cur;
            cur = after;
        }
        return pre;
    }
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* dummyNode = new ListNode(-1);
        dummyNode->next = head;
        ListNode* prel = NULL;
        ListNode* l = dummyNode;
        while (left--) {
            prel = l;
            l = l->next;
        }
        ListNode* aftr = NULL;
        ListNode* r = dummyNode;
        while (right--) {
            r = r->next;
        }
        aftr = r->next;
        r->next = NULL;
        prel->next = reverseList(l);
        while(prel->next) prel = prel->next;
        prel->next = aftr;
        return dummyNode->next;
    }
};

leetcode 24 两两交换链表中的节点

画图按照转换的逻辑步骤写代码,一次转换涉及到三个节点。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyNode = new ListNode();
        dummyNode->next = head;
        ListNode* cur = dummyNode;
        while (cur->next != nullptr && cur->next->next != nullptr) {
            ListNode* node1 = cur->next;
            ListNode* node2 = cur->next->next;
            ListNode* node3 = cur->next->next->next;
            cur->next = node2;
            node2->next = node1;
            node1->next = node3;
            cur = cur->next->next;
        }
        return dummyNode->next;
    }
};

leetcode 19 删除链表的倒数第 N 个结点(采用双指针fast和slow)

采用双指针,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾,删掉slow所指向的节点就可以了。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (n--) {
            fast = fast->next;
        }
        ListNode* pre = NULL;
        while (fast && slow) {
            fast = fast->next;
            pre = slow;
            slow = slow->next;
        }
        if (pre) pre->next = slow->next;
        else return slow->next;
        return head;
    }
};
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyNode = new ListNode();
        dummyNode->next = head;
        ListNode* fast = dummyNode;
        ListNode* slow = dummyNode;
        ListNode* preslow = nullptr;
        while (fast != nullptr) {
            while (n) {
                fast = fast->next;
                n--;
            }
            preslow = slow;
            slow = slow->next;
            fast = fast->next;
        }
        ListNode* tmp = slow;
        preslow->next = slow->next;
        delete tmp;
        return dummyNode->next;
    }
};

leetcode 876 链表的中间结点(采用双指针fast和slow)

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
};

leetcode 160 链表相交(两种方法)

解决这个问题的关键是,通过某些方式,让 p1 和 p2 能够同时到达相交节点 c1。

//求出两个链表的长度差值dst,先让长度较长的链表先走dst,然后两个链表一起走,遇到第一个相同的节点就是相等的
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int dista = 0;
        int distb = 0;
        int dist = 0;
        while (curA) {
            curA = curA->next;
            dista++;
        }
        while (curB) {
            curB = curB->next;
            distb++;
        }
        dist = abs(dista-distb);
        ListNode* curL;
        ListNode* curS;
        if (dista >= distb) {
            curL = headA;
            curS = headB;
        }
        else {
            curL = headB;
            curS = headA;
        }
        while (dist--) curL = curL->next;
        while (curL && curS) {
            if (curL == curS) {
                return curL;
            }
            curL = curL->next;
            curS = curS->next;
        }
        return NULL;
    }
};

我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。
如果这样进行拼接,就可以让 p1 和 p2 同时进入公共部分,也就是同时到达相交节点 c1。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        while (curA != curB) {
            if (!curA) curA = headB;
            else curA = curA->next;
            if (!curB) curB = headA;
            else curB = curB->next;
        }
        return curA;
    }
};

leetcode 141 环形链表(采用双指针fast和slow)

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        bool flag = false;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
            if (slow == fast) {
                flag = true;
                break;
            }
        }
        return flag;
    }
};

leetcode 142 环形链表 II(环形入口的判定条件)

//从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast != NULL && fast->next != NULL) {    //确保fast指针移动范围的有效
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2;
            }
        }
        return NULL;
    }
};

leetcode 328 奇偶链表

class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if (head == NULL) return NULL;
        ListNode* odd = head;
        ListNode* even = head->next;
        ListNode* evenStart = even;

        while (even != NULL && even->next != NULL) {
            odd->next = even->next;
            odd = odd->next;
            even->next = odd->next;
            even = even->next;
        }
        odd->next = evenStart;
        return head;
    }
};

leetcode 234 回文链表(采用slow和fast双指针,slow边遍历边逆转链表)

//采用快慢两个指针,快指针到达末尾,慢指针到达中间,慢指针在遍历过程中顺便翻转前面的链表
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        ListNode* cur = NULL;
        ListNode* pre = NULL;
        while (fast != NULL && fast->next != NULL) {
            cur = slow;
            slow = slow->next;
            fast = fast->next->next;
            cur->next = pre;
            pre = cur;
        }
        if (fast != NULL) {      //处理结点为奇数的情况
            slow = slow->next;
        }
        while (cur != NULL && slow != NULL) {
            if (cur->val != slow->val) {
                return false;
            }
            cur = cur->next;
            slow = slow->next;
        }
        return true;

    }
};

leetcode 21 合并两个有序链表(类似归并排序的Merge)

class Solution {
public:
	ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
		ListNode* dummyNode = new ListNode();
		ListNode* cur = dummyNode;
		while (list1 != NULL && list2 != NULL) {
			if (list1->val < list2->val) {
				cur->next = list1;
				list1 = list1->next;
			}
			else {
				cur->next = list2;
				list2 = list2->next;
			}
			cur = cur->next;
		}
		if (list1 != NULL) {
			cur->next = list1;
		}
		if (list2 != NULL) {
			cur->next = list2;
		}
		return dummyNode->next;
	}
};

leetcode 2 两数相加

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* dummyNode = new ListNode();
        ListNode* cur = dummyNode;
        int carry = 0;

        while (l1 != NULL || l2 != NULL) {
            int val1 = l1 == NULL ? 0 : l1->val;
            int val2 = l2 == NULL ? 0 : l2->val;
            int sum = val1 + val2 + carry;
            carry = sum / 10;
            sum = sum % 10;         
            cur->next = new ListNode(sum);;
            cur = cur->next;
            if (l1 != NULL) l1 = l1->next;
            if (l2 != NULL) l2 = l2->next;
        }

        if (carry == 1) {
            cur->next = new ListNode(1);
        }

        return dummyNode->next;
    }
};
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {       
        int carry = 0;
        ListNode* dummyNode = new ListNode();
        ListNode* r = dummyNode;
        while (l1 != NULL && l2 != NULL) {
            int a = l1->val;
            int b = l2->val;
            int c = (a + b + carry) % 10;
            carry = (a + b + carry) / 10;
            ListNode* p = new ListNode(c);
            r->next = p;
            r = p;
            l1 = l1->next;
            l2 = l2->next;
        }
        ListNode* q;
        if (l1 != NULL) q = l1;
        else q = l2;
        while (q != NULL) {
            int a = q->val;
            int c = (a + carry) % 10;
            carry = (a + carry) / 10;
            ListNode* p = new ListNode(c);
            r->next = p;
            r = p;
            q = q->next;
        }
        if (carry == 1) {
            ListNode* p = new ListNode(carry);
            r->next = p;
            r = p;
        }
        return dummyNode->next;
    }
};

leetcode 430 扁平化多级双向链表

//采用迭代法,按照段进行遍历,将其链接起来
class Solution {
public:
    Node* flatten(Node* head) {
        Node* dummyNode = new Node();
        dummyNode->next = head;

        while (head != NULL) {
            if (head->child != NULL) {
                Node* tmp = head->next;
                head->next = head->child;
                head->child->prev = head;
                Node* last = head->child;
                head->child = NULL;
                while (last->next != NULL) {
                    last = last->next;
                }
                last->next = tmp;
                if(tmp != NULL) tmp->prev = last;
            }
            head = head->next;
        }
        return dummyNode->next;
    }
};
//采用栈来保存节点
class Solution {
public:
    Node* flatten(Node* head) {
        Node* dummy = new Node();
        dummy->next = head;
        stack<Node*> sck;
        while (head != NULL) {
            if (head->child != NULL) {            //当该节点处有child分支时,并入该分支进主干
                Node* tmp = head->next;
                head->next = head->child;
                head->child->prev = head;
                head->child = NULL;               //为了恢复完整的双链表结构,child指针合入用完后需要置空
                if (tmp != NULL) sck.push(tmp);   //压栈,以备后面续接链表
            }
            else {     // head->child == NULL
                if (head->next == NULL && !sck.empty()) {    //续接链表
                    Node* tmp = sck.top();
                    sck.pop();
                    head->next = tmp;
                    tmp->prev = head;
                }
            }
            head = head->next;        //每轮处理完后,接着处理下一个结点,直到所有节点都被处理完
        }
        return dummy->next;
    }
};

leetcode 138 复制带随机指针的链表

采用递归进行处理

class Solution {
    unordered_map<Node*, Node*> hashMap;
public:
    Node* copyRandomList(Node* head) {
        if (!head) return NULL;
        Node* newNode = new Node(head->val);
        hashMap[head] = newNode; 
        newNode->next = copyRandomList(head->next);
        if (head->random) {
            newNode->random = hashMap[head->random];
        }
        return newNode;
    }
};

采用迭代法

class Solution {
public:
    Node* copyRandomList(Node* head) {
        unordered_map<Node*, Node*> hashMap;
        Node* cur = head;
        while (cur != NULL) {
            Node* tmp = new Node(cur->val);
            hashMap[cur] = tmp;
            cur = cur->next;
        }
        cur = head;
        while (cur != NULL) {
            Node* tmp = hashMap[cur];
            if(cur->next) tmp->next = hashMap[cur->next];
            else tmp->next = NULL;
            tmp->random = hashMap[cur->random];
            cur = cur->next;
        }
        return hashMap[head];
    }
};
class Solution {
public:
    Node* copyRandomList(Node* head) {
        if (head == NULL) return NULL;
        unordered_map<Node*, int> hashMap;
        vector<Node*> vec;
        Node* cur = head;
        int idx = 0;
        while (cur != NULL) {
            hashMap.insert(pair<Node*, int>(cur, idx));
            vec.push_back(new Node(cur->val));
            cur = cur->next;
            idx++;
        }  
        cur = head;
        idx = 0;
        vec.push_back(NULL);
        while (cur != NULL) {
            vec[idx]->next = vec[idx+1];
            Node* tmp = cur->random;
            if (tmp == NULL) {
                vec[idx]->random = NULL;
            }
            else {
                vec[idx]->random = vec[hashMap[tmp]];
            }
            cur = cur->next;
            idx++;
        }
        return vec[0];
    }
};

leetcode 61 旋转链表

//本质上是将尾部向前数第K个元素作为头,原来的头接到原来的尾上
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if (k == 0 || !head || !head->next) return head;
        int cnt = 1;
        ListNode* cur = head;
        while (cur->next != NULL) {
            cnt++;
            cur = cur->next;
        }
        k = k % cnt;
        if(k == 0) return head;
        cur->next = head;        //需要翻转,首尾相连
        for (int i = 0; i < cnt - k; i++) {    //找到倒数第k+1个节点
            cur = cur->next;
        }
        ListNode* newHead = cur->next;
        cur->next = NULL;
        return newHead;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值