链表问题汇总

在这里插入图片描述

//快慢指针
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL)
            return head;
        ListNode* pre = NULL, *cur = head, *tmp;

        while(cur != NULL){
            tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }

        return pre;

    }
};
//递归
class Solution {
public:
    ListNode* reverse(ListNode* pre, ListNode* cur){
        if(cur == NULL){
            return pre;
        }
        ListNode* tmp = cur->next;
        cur->next = pre;
				
				// 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
        // pre = cur;
        // cur = temp;
        return reverse(cur, tmp);
    }
    ListNode* reverseList(ListNode* head) {
        if(head == NULL)
            return head;
				
				// 和双指针法初始化是一样的逻辑
        // ListNode* cur = head;
        // ListNode* pre = NULL;
        return reverse(NULL, head);
    }
};

在这里插入图片描述

设置虚拟头结点的作用:
移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在写代码的时候也会发现,需要单独写一段逻辑来处理移除头结点的情况。

设置虚拟头结点后, 原链表的所有节点就都可以按照统一的方式进行移除了。

//快慢指针
//fast先走n+1步,然后slow开始同步走
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;

        ListNode* fast = dummyHead, *slow = dummyHead;
        for(int i = 0; i <= n ; i++)
            fast = fast->next;
        
        
        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
        }

        ListNode* del = slow->next;
        slow->next = del->next;
        delete del;
        ListNode* ret = dummyHead->next;
        delete dummyHead;

        return ret;
    }
};

在这里插入图片描述

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* cur = dummyHead->next;
        ListNode* pre = dummyHead;

        while(cur != NULL){
            if(cur->val == val){
                ListNode* del = cur;
                pre->next = cur->next;
                cur = pre->next;
                delete del;
            }
           else{
               pre = cur;
               cur = cur->next;
           } 
            
        }

        ListNode* ret = dummyHead->next;
        delete dummyHead;

        return ret;
    }
};

在这里插入图片描述

题解:https://leetcode-cn.com/problems/reorder-list/solution/dong-hua-yan-shi-kuai-man-zhi-zhen-143-z-4kmk/

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;

        while(fast != NULL && fast->next != NULL){
            fast = fast->next->next;
            slow = slow->next;
        }

        return slow;
    }
};

在这里插入图片描述

class Solution {
public:
    bool hasCycle(ListNode *head) {
        
        ListNode* slow = head, *fast = head;

        while(fast && fast->next){
            slow = slow->next;
            fast = fast->next->next;

            if(fast == slow) return true;
        }

        return false;
    }
};

设置快慢指针,慢指针每走一步,快指针走两步,如果存在环,则快指针肯定会先走进环,慢指针后进入环。
又因为快指针走的比慢指针快,故二者终会相邻,然后再慢指针走一步,快指针走两步,二者就会相遇。

在这里插入图片描述

1.找到链表中间结点(若结点个数为偶数个,则返回中间第一个结点)
2.反转中间结点后面的链表
3.将链表前半部分和反转后的后半部分进行合并
题解:https://leetcode-cn.com/problems/reorder-list/solution/dong-hua-yan-shi-kuai-man-zhi-zhen-143-z-4kmk/

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

        return slow; //为偶数个的话,返回中间两个结点的前面一个
    }

    ListNode* reverseList(ListNode* head){
        ListNode* pre = NULL, *cur = head, *tmp;
        while(cur != NULL){
            tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }

        return pre;
    }

    void mergeList(ListNode* head1, ListNode* head2){
        ListNode* next1 = NULL, *next2 = NULL;

        while(head1 != NULL && head2 != NULL){
            next1 = head1->next;
            next2 = head2->next;

            head1->next = head2;
            head1 = next1;

            head2->next = head1;
            head2 = next2;
        }
    }

    void reorderList(ListNode* head) {
        if(head == NULL)
            return;
        
        ListNode* mid = findMin(head);

        //中间结点后面的部分进行反转
        ListNode* head2 = mid->next;
        mid->next = NULL;
        head2 = reverseList(head2);

        ListNode* head1 = head;
        mergeList(head1, head2);

    }
};

在这里插入图片描述

  1. 先求链表长度,若k大于链表长度,则用k对长度取余。
  2. 求倒数第k个结点的前一个结点
  3. 让倒数第k个结点成为头结点
    题解:https://leetcode-cn.com/problems/rotate-list/solution/dong-hua-yan-shi-kuai-man-zhi-zhen-61-xu-7bp0/
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(k == 0 || head == NULL)
            return head;
        ListNode* tmp = head;
        int cnt = 0;
        while(tmp != NULL){
            cnt++;
            tmp = tmp->next;
        }
        k = k % cnt;



        ListNode* slow = head, *fast = head, *fastPre = head;

        for(int i = 0; i < k+1; i++)
            fast = fast->next;
        
        for(int i = 0; i < k; i++)
            fastPre = fastPre->next;
        
        while(fast != NULL){
            fast = fast->next;
            slow = slow->next;
            fastPre = fastPre->next;
        }

        fastPre->next = head;
        head = slow->next;
        slow->next = NULL;



        return head;
        

    }
};

在这里插入图片描述
在这里插入图片描述

//归并排序
//空复O(logn) 时复O(nlogn)
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;
        
        ListNode* slow = head, *fast = head;
        
        while(fast->next != NULL && fast->next->next != NULL){
            slow = slow->next;
            fast = fast->next->next;
        }
        
        ListNode* rightHead = slow->next;
        slow->next = NULL;  //cut
        
        ListNode* left = sortList(head);
        ListNode* right = sortList(rightHead);
        
        return Merge(left, right);
        
    }
    
    ListNode* Merge(ListNode* h1, ListNode* h2){
        ListNode* dummyHead = new ListNode(0);
        ListNode* p = dummyHead;
        
        while(h1 != NULL && h2 != NULL){
            if(h1->val < h2->val){
                p->next = h1;
                h1 = h1->next;
            }
            else{
                p->next = h2;
                h2 = h2->next;
            }
            
            p = p->next;
        }
        
        if(h1)
            p->next = h1;
        else
            p->next = h2;
        
        
        return dummyHead->next;
    
    }
};

在这里插入图片描述
前缀和+hashmap
删除结点就要用到dummyhead

class Solution {
public:
    ListNode* removeZeroSumSublists(ListNode* head) {
        ListNode* cur = head;

        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;

        int preSum = 0;
        unordered_map<int, ListNode*> mp;
        mp[0] = dummyHead;

        while(cur != NULL){
            preSum += cur->val;
            if(mp.find(preSum) != mp.end()){
                ListNode* tmp = mp[preSum]->next;
                mp[preSum]->next = cur->next;

                int tmpSum = preSum;
                while(tmp != cur){
                    tmpSum += tmp->val;
                    mp.erase(tmpSum);
                    tmp = tmp->next;
                }
            }else{
                mp[preSum] = cur;
            }
            cur = cur->next;
        }
        ListNode* ret = dummyHead->next;
        delete dummyHead;

        return ret;

    }
};

在这里插入图片描述

整个链表分为已反转区、待反转区和未反转区
指针分别为 pre, start end,next;

class Solution {
public:
    ListNode* reverseList(ListNode* head){
        ListNode* pre = NULL, *cur = head;

        while(cur != NULL){
            ListNode* tmp = cur->next;
            cur->next = pre;

            pre = cur;
            cur = tmp;
        }

        return pre;
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
        if(head->next == NULL || k == 1)
            return head;
        
        
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* pre = dummyHead;
        ListNode* end = head, *start = head;

        while(start != NULL){
            int tmp = k - 1;
            while(tmp && end != NULL){
                tmp--;
                end = end->next;
            }
            if(end == NULL)
                break;

            ListNode* next = end->next;
            end->next = NULL;

            pre->next = reverseList(start);
            pre = start;

            start->next = next;

            start = next;
            end = start;
        }


        ListNode* ret = dummyHead->next;
        delete dummyHead;

        return ret;
        
    }
};

在这里插入图片描述
哈希表

  1. 首先构造原链表节点宇新节点之间的哈希映射关系。
  2. 构造每个节点的next和random。
class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head == NULL) return head;

        unordered_map<Node* , Node*> mp;

        Node* cur = head;
		
		//1. 首先构造原链表节点宇新节点之间的哈希映射关系。
        while(cur){
            mp[cur] = new Node(cur->val);
            cur = cur->next;
        }

		//2. 构造每个节点的next和random。
        cur = head;
        while(cur){
            mp[cur]->next = mp[cur->next];
            mp[cur]->random = mp[cur->random];
            cur = cur->next;
        }

        return mp[head];

    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值