链表相关题解总结

链表的一些基础知识就不赘述了 自己总结了几个链表的几种题型 和基础方法

有些题型的相似方法就一概而过 都是自己总结 有意见希望多多指出 我好加以修改

合并两个有序数组

leetcode 21

1.双指针  引入一个结果结点 对其比较遍历插入 

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* prehead=new ListNode(-1);
        ListNode* prev=prehead;
        while(l1!=nullptr&&l2!=nullptr){
            if(l1->val<l2->val){
                prev->next=l1;
                l1=l1->next;
            }else{
                prev->next=l2;
                l2=l2->next;
            }
            prev=prev->next;

        }
        prev->next=l2==nullptr? l1:l2;
        return prehead->next; 
    }

2.递归 对于此题完全可以不用引入结果链表 直接一个链表遍历插入到另一个链表中 其中插入即为链表的常用操作之一  以下用递归表示

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == nullptr) return l2;
        if(l2 == nullptr) return l1;
        if(l1->val < l2->val){
            l1->next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        l2->next = mergeTwoLists(l1,l2->next);
        return l2;
    }

对比而言 递归的较为简洁 但是递归总是时间复杂度略高 0(m+n)

删除排序链表中的重复元素

leetcode 83

 1.对其遍历 若currentnode.val == currentnode.next.val  则  currentnode.next = currentnode.next.next    对其链表遍历实行  即可解决

    ListNode* deleteDuplicates(ListNode* head) {
        if(head==nullptr){
            return head;
        }
        ListNode* currentnode = head;
        while(currentnode->next != nullptr){
            if(currentnode->val == currentnode->next->val){
                currentnode->next = currentnode->next->next;
            }else {
                currentnode = currentnode->next;
            }
        }
        return head;
    }

2.递归  本质就是将链表压栈后倒序处理

这里直接写一下状态转移方程  

head.next = deleteduplicates(head.next);

此题也一样递归的方法  代码十分简洁  但是复杂度比较高  而且递归其实 不太好理解    我比较建议  使用上述解法比较好  代码写起来也比较流畅

环形链表

leetcode 141    142

 

 1.hanh表   逐个遍历链表  对其检查是否存在hash表中  不在则插入hash表中 在的话则返回true

注意    我们插入的是链表  而不是val值     其中空间复杂度 较高为o(n)

    // bool hasCycle(ListNode *head) {
    //     unordered_set<ListNode*> seen;
    //     while(head!= nullptr){
    //         if(seen.count(head)){
    //             return true;
    //         }
    //         seen.insert(head);
    //         head = head -> next;
    //     }             
    //     return false;
    // }

2.Floyd    环形链表有一种通用解法floyd解法 具体可以自行百度  我们这里简单的可以理解为快慢指针  fast index每次走两次  slow index 每此走一次  可以理解为追击问题   若存在环  即必定快慢指针会相遇   

        bool hasCycle(ListNode *head) {
            if(head == nullptr) return false;
            ListNode* slowptr = head,* fastptr = head;
            while(fastptr->next !=nullptr&& fastptr->next->next !=nullptr){
                slowptr =slowptr->next;
                fastptr =fastptr->next->next;
                if(slowptr == fastptr ) return true;
            }
            return false;
    }

这题放在一起说的原因是因为 只是需要返回环形链表的头节点 对此我们分析一下 发现第一种hash表的解法 更为容易理解 但是同样的问题就是空间复杂度不可控  对此我们同样使用Floyd解法

1.Floyd  当我们快慢指针相遇的时候  我们将慢指针重新回到head结点  这时快慢指针同时每次移动一个结点  当快慢指针再次相遇时  这个结点即为环形链表的头节点  这个如果不能理解的话可以手动画一画

    ListNode *detectCycle(ListNode *head) {
        if(head == nullptr) return NULL;
        ListNode* slowptr = head ,*fastptr = head;
        bool tag = false;
        while(fastptr->next != nullptr && fastptr->next->next!=nullptr){
            slowptr = slowptr->next;
            fastptr = fastptr->next->next;
            if(slowptr == fastptr){
                tag = true;
                break;
            }
        }
        if(tag){
            slowptr = head;
            while(slowptr != fastptr){
                slowptr = slowptr->next;
                fastptr = fastptr->next;
            }
            return slowptr;
        }
        return NULL;
    }

 相交链表

leetcode 160

1.暴力穷举  将A和B的所有元素进行比较  复杂度为o(mn)  这里不在赘述

2.hash  将a的元素放进  hash中   对b遍历 比较    空间和时间复杂度都比较高

3.双指针  index1 =heada index2 = headb  遍历当其中一个指针到达末尾 返回到另一个链表的头节点  若符合相交链表 则必定存在index1=index2  否者当循环两次之后不存在则返回false  

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == nullptr || headB == nullptr) return NULL;
        ListNode *pa = headA,*pb = headB;
        while(pa != pb){
            pa = pa==nullptr? headB:pa->next;
            pb = pb==nullptr? headA:pb->next;
        }
        return pa;
    }

 4.首先获得两个链表的长度  length1  和length2   我们令d=length1-length2 绝对值 对于长链表而言先移动d次  再一起移动两个指针 当两个指针相等  则存在

这种方法为模拟   代码实现较为流畅 不在赘述   感兴趣的可以自己实现一下  代码较为复杂 但是复杂度控制很明显

反转链表

leetcode 206

此题为链表的常见操作之一   不过多赘述 直接给出题解

    ListNode* reverseList(ListNode* head) {
        ListNode *prenode  = nullptr;
        ListNode *curr = head;
        while(curr != nullptr){
            ListNode *next = curr->next;
            curr->next = prenode;
            prenode = curr;
            curr = next;
        }
        return prenode;
    }

 回文链表

leetcode 234

 对于此题我们可以发现  直接将链表等量分割两部分 后一部分进行上一题的反转  依次比较即可

但是对于等量分割我们给出两种思路 第一种 遍历求n  再次遍历求n/2 

第二种双指针 当快指针到达链表尾部 慢指针为中间结点

   ListNode* reverse(ListNode* head){
       ListNode *prev = nullptr;
       while(head!=nullptr){
           ListNode* next = head->next;
           head->next = prev ;
           prev = head;
           head = next;
       }
       return prev;
   }
    bool isPalindrome(ListNode* head) {
        ListNode* fast = head,*slow = head;
        while(fast!= nullptr && fast->next != nullptr){
            fast = fast -> next -> next;
            slow = slow -> next;
        }
        slow = reverse(slow);
        fast = head;
        while(slow != nullptr){
            if(fast->val != slow->val){
                return false;
            }
            fast = fast->next;
            slow = slow->next;
        }
        return true;
    }

链表的中间结点

leetcode 876

此题为快慢指针的经典用例   不过多赘述 

链表中倒数第k个节点

剑指offer 22

 

1.倒数第k个结点即为 正数第n+1-k 个 遍历即可

2.快指针先移动k-1 再两个指针同时移动 当快指针到最后 慢指针即为所求

3.hashmap <key  值>  直接储存 不太推荐

总结

对此 我已经将本人接触到的链表的基本解法都总结于此 有补充的可以评论 希望加以完善谢谢

   

cs202  zhoujie

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值