专题:链表(已完结)

1.移除链表元素
就是续签prenode curnode 需要注意本地使用虚拟头节点逻辑更加简单

/**
 * 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* dummyHead = new ListNode();
      dummyHead->next=head;
      ListNode* prenode= dummyHead;
      ListNode* curnode= dummyHead->next;
      while(curnode!=nullptr){
        if(curnode->val==val){
            ListNode* delenode=curnode;
            prenode->next=curnode->next;
            curnode=curnode->next;
            delete delenode;
        }else{
            prenode=curnode;
            curnode=curnode->next;
        }

      }
      auto result = dummyHead->next;
      delete dummyHead;
      return result;
    }
};

2.设计链表

class MyLinkedList {
    struct LinkList{
        LinkList * next;
        int val;
        LinkList():val(0),next(nullptr){}

        LinkList(int value):val(value),next(nullptr){}
    };
public:
    MyLinkedList() {
        dummy = new LinkList();
    }
    
    int get(int index) {
        LinkList * cur = dummy->next;
        int len =0;
        while(cur!=nullptr){
            len++;
            cur=cur->next;
        }
        if(index>=len){
            // 下标无效
            return -1;
        }
        cur = dummy->next;
        while(index--){
            cur=cur->next;
        }
        return cur->val;

    }
    
    void addAtHead(int val) {
        LinkList * head = new LinkList(val);
        head->next = dummy->next;
        dummy->next = head;
    }
    
    void addAtTail(int val) {
        LinkList * tailp = new LinkList(val);
        LinkList * cur = dummy;
        while(cur->next!=nullptr){
            cur = cur->next;
        }
        cur->next = tailp; 
    }
    
    void addAtIndex(int index, int val) {

        LinkList * cur = dummy->next;
        int len =0;
        while(cur!=nullptr){
            len++;
            cur=cur->next;
        }
        if(index>len){
            return;
        }
        if(index==len){
            addAtTail(val);
            return;
        }

        LinkList * pre = dummy;
        cur = dummy->next;
        while(index--){
            pre=cur;
            cur=cur->next;
        }
        // 直接插入pre后面就可以了
        LinkList * pnewnode = new LinkList(val);
        pnewnode->next=pre->next;
        pre->next=pnewnode;
    }
    
    void deleteAtIndex(int index) {
        LinkList * cur = dummy->next;
        int len =0;
        while(cur!=nullptr){
            len++;
            cur=cur->next;
        }
        if(index>=len){
            // 下标无效
            return;
        }
        LinkList * pre = dummy;
        cur = dummy->next;
        while(index--){
            pre=cur;
            cur=cur->next;
        }
        pre->next = cur->next;
    }
    LinkList * dummy =nullptr;
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

3.反转链表
主要思路 使用虚拟有节点 然后遍历每个节点 直接插入头部即可

/**
 * 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* dummyHead = new ListNode();
        dummyHead->next=nullptr;

        ListNode* cur = head;
        while(cur!=nullptr){
            ListNode* nextnode = cur->next;
            cur->next=dummyHead->next;
            dummyHead->next=cur;
            cur=nextnode;
        }
        ListNode* result = dummyHead->next;
        delete  dummyHead;
        return result;
    }
};

4.两两交换链表中的节点
使用虚拟头结点 找到pre 然后取 待交换的两个节点

            ListNode* nextnode1=pre->next;
            ListNode* nextnode2=pre->next->next;

另外注意 交换之后 pre更新位置不是两个节点的下一个节点 而是

pre=nextnode1;
/**
 * 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* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode();
        dummyHead->next=head;
        ListNode* pre=dummyHead;
        while(pre->next!=nullptr && pre->next->next!=nullptr){
            ListNode* nextnode1=pre->next;
            ListNode* nextnode2=pre->next->next;
            ListNode* tempnode=nextnode2->next;
            nextnode2->next=nextnode1;
            nextnode1->next=tempnode;
            pre->next=nextnode2;

            pre=nextnode1;
        }
        ListNode* result=dummyHead->next;
        delete dummyHead;
        return result;

    }
};

5.删除链表的倒数第N个节点

/**
 * 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* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyhead = new ListNode();
        dummyhead->next = head;
        ListNode *slow=dummyhead;
        ListNode *fast=dummyhead;
        while(n--){
            // 快指针先走n个节点
            fast=fast->next;
            if(fast==nullptr){
                break;
            }
        }
        if(fast==nullptr){
            // 证明n已经大于节点个数 无意义
            delete dummyhead;
            return head;
        }
        while(fast->next!=nullptr){
            slow=slow->next;
            fast=fast->next;
        }
        ListNode *delenode=slow->next;
        slow->next=delenode->next;
        delete delenode;
        ListNode * result = dummyhead->next;;
        delete dummyhead;
        return result;

    }
};

6.链表相交
主要思路:
方法一:首先长的链表先移动差值个单位 然后 然后判断两个链表此时位置是否是同一个节点 不是的话一起一个单位 再次判断 还不是的话 再次移动 如此反复判断 直到其中一个链表移动到末尾即可。

/**
 * 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) {
        int lenA =0;
        ListNode *curA=headA;
        while(curA){
            lenA++;
            curA=curA->next;
        }

        int lenB =0;
        ListNode *curB=headB;
        while(curB){
            lenB++;
            curB=curB->next;
        }
        // cur1指向更长的
        ListNode * cur1=headA;
        ListNode * cur2=headB;
        int k = abs(lenA-lenB);
        if(lenA<lenB){
            swap(cur1,cur2);
        }
        while(k--){
            cur1=cur1->next;
        }
        while(cur1!=nullptr){
            if(cur1==cur2){
                return cur1;
            }else{
                cur1=cur1->next;
                cur2=cur2->next;
            }

        }
        return nullptr;
    }
};

方法二:

/**
 * 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) {
      ListNode *curA= headA;
      ListNode *curB= headB;
      while(curA!=curB){
          curA=curA==NULL?headB:curA->next;
          curB=curB==NULL?headA:curB->next; 
      }
      return curA;
    }
};

7.环形链表II
注意
快慢指针都是从第一个节点出发

        ListNode *slow=head;
        ListNode *fast=head;

循环体内慢指针每次走一个节点 快指针每次走两个节点

             slow = slow->next;
             fast=fast->next->next;

如果快慢指针不相遇一直这么走 直到fastnullptr或者fast->nextnullptr结束 相遇的话 直接重新设置两个指针 一个从头节点出发 一个从相遇节点出发 每次比较 如果不是同一个节点 每次都走一个节点长度 直到相遇即可

                ListNode *cur1=head;
                ListNode *cur2=slow;
                while(cur1!=cur2){
                    cur1=cur1->next;
                    cur2=cur2->next;
                }
                return cur1;

完整代码如下

/**
 * 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 *slow=head;
        ListNode *fast=head;
        while(fast!=nullptr&&fast->next!=nullptr){
             slow = slow->next;
             fast=fast->next->next;
            if(fast==slow){
                ListNode *cur1=head;
                ListNode *cur2=slow;
                while(cur1!=cur2){
                    cur1=cur1->next;
                    cur2=cur2->next;
                }
                return cur1;
            }

        }
        return nullptr;
        
    }
};

额外常见链表题目补充
8.合并两个有序链表
思路:采用尾插法 循环结束后 最后看那个节点不为空 直接全部拼接在尾部即可。

/**
 * 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode * dummy = new ListNode();
        ListNode * tail = dummy;
        while(list1!=nullptr && list2!=nullptr){
            if(list1->val>list2->val){
                tail->next=list2;
                tail = list2;
                list2=list2->next;
            }else{
                tail->next=list1;
                tail = list1;
                list1=list1->next;
            }
        }
        if(list1!=nullptr){
            tail->next = list1;
        }
        if(list2!=nullptr){
            tail->next = list2;
        } 
        return dummy->next;
    }
};

9.重排链表
主要思路是 先将链表平均分成两个链表(快指针要先走一步) 然后将第二个链表直接反转(头插法) 然后 将两个链表交叉连接(尾插法)

/**
 * 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* reverse(ListNode* secondhead){
        ListNode* dummy = new ListNode();
        while(secondhead!=nullptr){
            ListNode* next = secondhead->next;

            secondhead->next = dummy->next;
            dummy->next = secondhead;

            secondhead=next;
        }
        return dummy->next;

    }
    void reorderList(ListNode* head) {
        // 主要思路是 先将链表平均分成两个链表(快指针要先走一步) 然后将第二个链表直接反转(头插法) 然后 将两个链表交叉连接(尾插法) 
        ListNode* slow,* fast;
        slow=head;
        // 终端 将一个链表平均成两个链表 快指针最开始 一定要先走一步 题目中至少有一个节点 因此此处不用加以判断 head==null?
        fast=head->next;
        while(fast!=nullptr&&fast->next!=nullptr){
            slow=slow->next;
            fast=fast->next->next;
        }
        ListNode* secondhead = slow->next;
        // 一定要注意断链
        slow->next=nullptr;

        ListNode* firsthead = head;
        
        // 头插法将第二个链表反转
        secondhead=reverse(secondhead);

        
        ListNode* dummy = new ListNode();
        // 尾插法
        ListNode*  tail = dummy;
        int first=true;
        while(firsthead!=nullptr && secondhead!=nullptr){
            if(first){
                tail->next = firsthead;
                tail=firsthead;
                firsthead=firsthead->next;
            }else{
                tail->next = secondhead;
                tail=secondhead;
                secondhead=secondhead->next;
            }
            first=!first;
        }
        if(firsthead!=nullptr){
            tail->next = firsthead;
        }
        if(secondhead!=nullptr){
            tail->next = secondhead;
        }
        head = dummy->next;
        return;  
    }
};

10.奇偶链表
思路:维持两个链表 采用尾插法 注意拆成两个链表的时候 需要将尾部置为空

        while(head!=nullptr){
            ...
            if(i%2!=0){
                // 尾插法
                
                cur1->next=nullptr;
            }else{
                // 尾插法

                cur2->next=nullptr;
            }
             ...
        }

完整代码

/**
 * 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* oddEvenList(ListNode* head) {
        ListNode* dummy1 = new ListNode();
        ListNode* tail1=dummy1;

        ListNode* dummy2 = new ListNode();
        ListNode* tail2=dummy2;
        int i=1;
        while(head!=nullptr){
            if(i%2!=0){
                // 奇数
                tail1->next = head;
                tail1=head;
                head=head->next;

                tail1->next =nullptr;


            }else{
                // 偶数
                tail2->next = head;
                tail2=head;
                head=head->next;

                tail2->next =nullptr;

            }
            
            i++;
        }
        tail1->next  = dummy2->next;
        return dummy1->next;
    }
};

11.排序奇升偶降链表

思路 先将一个链表按照奇偶拆成两个链表 注意每次才有尾插法拼接节点的时候 需要将尾部置为空(防止最后两个链表没有完全断链)

        while(head!=nullptr){
            ...
            if(i%2!=0){
                // 尾插法
                
                cur1->next=nullptr;
            }else{
                // 尾插法

                cur2->next=nullptr;
            }
             ...
        }

完整代码

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
     ListNode* reverse(ListNode* head){
        ListNode* dummy=new ListNode(0);
        while(head!=nullptr){
            auto nextnode  = head->next;

            head->next= dummy->next;
            dummy->next=head;

            head=nextnode;
        }
        return dummy->next;

     }
    ListNode* sortLinkedList(ListNode* head) {
        // write code here
        ListNode* dummy1=new ListNode(0);
        ListNode* dummy2=new ListNode(0);
        ListNode* cur1 = dummy1;
        ListNode* cur2 = dummy2;
        int i =1;
        while(head!=nullptr){
            auto nextnode = head->next;
            if(i%2!=0){
                // 尾插法
                cur1->next=head;
                cur1=head;
                cur1->next=nullptr;
            }else{
                // 尾插法
                cur2->next=head;
                cur2=head;
                cur2->next=nullptr;
            }
            head=nextnode;
            i++;
        }
        // 借助头结点反转链表
        cur2 = reverse(dummy2->next);
        cur1 = dummy1->next;
        
        // 下面相当于合并两个有序链表
        ListNode* dummy=new ListNode(0);
        ListNode* tail=dummy;
        while(cur2!=nullptr&&cur1!=nullptr){
            if(cur2->val<cur1->val){
                tail->next = cur2;
                tail =cur2;

                cur2=cur2->next;

            }else{
                tail->next = cur1;
                tail =cur1;

                cur1=cur1->next;
            }

        }
        if(cur2!=nullptr){
            tail->next = cur2;
        }
        if(cur1!=nullptr){
            tail->next = cur1;
        }

        return dummy->next;
        

    }
};

12.判断回文链表

/**
 * 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 {

private:
    ListNode* reverse(ListNode* head){
        ListNode* dummy = new ListNode(0);
        while(head!=nullptr){
            auto nextnode = head->next;

            head->next=dummy->next;
            dummy->next=head;

            head=nextnode;
        }
        return dummy->next;
    }
public:
    bool isPalindrome(ListNode* head) 
    {
        // 先找到中间位置
        ListNode* slow = head;
        // 条件可知 至少一个节点 也就是此处不会越界
        ListNode* fast = head->next;
        while(fast!=nullptr && fast->next!=nullptr){
            slow=slow->next;
            fast=fast->next->next;
        }

        ListNode* second = slow->next;
        // 链表的反转
        second = reverse(second);

        slow->next=nullptr;
        ListNode* first = head;
        while(first!=nullptr&&second!=nullptr){
            if(first->val!=second->val){
                return false;
            }
            first=first->next;
            second=second->next;
        }
        return true;
    }
};

11. K 个一组翻转链表

/**
 * 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 {
    ListNode* reverse(ListNode*start){
        ListNode* dummy=new ListNode();
        while(start!=nullptr){
            auto nextnode = start->next;
            start->next=dummy->next;
            dummy->next=start;
            start=nextnode;
        }
        return dummy->next;
    }
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* pre,*start,*end,*nextnode;
        ListNode* dummy=new ListNode();
        dummy->next = head;
        pre = dummy;
        start  = dummy->next;
        end  = nullptr;
        nextnode = nullptr;
        while(start!=nullptr){
            int i;
            end =start;
            for(i=1;i<=k-1&&end!=nullptr;i++){
                end=end->next;
            }
            if(end==nullptr){
                // 长度已经不够 直接返回即可
                return dummy->next;
            }
            nextnode = end->next;
            //断链
            end->next=nullptr;
            pre->next = nullptr;

           reverse(start);

           pre->next=end;
           start->next = nextnode;

           pre = start;
           start=nextnode;
        }
        return dummy->next;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值