代码随想录-设计链表

1.设计链表
在这里插入图片描述

class MyLinkedList {
public:
    struct LinkedNode{
        int val;
        struct LinkedNode* next;
        LinkedNode(int val):val(val),next(nullptr){} //这里待会搞清楚
    };
    MyLinkedList() {
        _dummyHead=new LinkedNode(0);
        _size=0;
    }
    
    int get(int index) {
        if(index<0||index>(_size-1)) return -1;
        LinkedNode *cur=_dummyHead->next; //让cur最终指向第index个结点
        while(index--){
            cur=cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkedNode* newNode=new LinkedNode(val);
        newNode->next=_dummyHead->next;
        _dummyHead->next=newNode;
        _size++;
    }
    
    void addAtTail(int val) {
        LinkedNode* cur=_dummyHead; //前面两种cur都是从第一个结点开始,这里不行,因为假如是空链表,cur指向第一个结点就是空,根本无法进行插入操作
        LinkedNode *newNode=new LinkedNode(val);
        while(cur->next)    cur=cur->next;//保证了cur最终指向的是最后一个结点
        cur->next=newNode;
        _size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index>_size)    return;
        if(index==_size)   {
            addAtTail(val);
            return;
        }
        LinkedNode* cur=_dummyHead;
        LinkedNode* newNode=new LinkedNode(val);
        while(index--)  cur=cur->next;
        newNode->next=cur->next;
        cur->next=newNode;
        _size++;

    }
    
    void deleteAtIndex(int index) {
        if(index<0||index>=_size)   return;
        LinkedNode* cur=_dummyHead; //要删除第index个结点,就要找第index-1个结点
        while(index--)  cur=cur->next;
        LinkedNode* delNode=cur->next;
        cur->next=cur->next->next;
        delete delNode;
        _size--;

    }

private:
    int _size;
    LinkedNode* _dummyHead;
};

/**
 * 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);
 */

思路:感觉这道题唯一要注意的就是怎么寻找合适的插入点:
(1)对于get函数,初始化cur指针指向第一个结点,而不是头结点,再利用while(index--) cur=cur->next;就能够让cur最终指向第index个结点。

LinkedNode *cur=_dummyHead->next; //让cur最终指向第index个结点
while(index--)	cur=cur->next;

(2)对于addAtTail函数,最开始,我是直接想参照get函数的方法,初始化cur指针指向第一个结点,然后利用上面的方法,即count=(_size-1); while(count--) cur=cur->next;,但是仔细考虑就会发现当链表是空链表时这样是不行的,因为这种方法只有在链表不为空时适用,然后才可以通过这个方法找到链表的最后一个元素,但当链表是空链表时,cur指针就被初始化为空指针,而合理的方法是当链表为空时,cur应该指向头结点,这样才能进行插入操作,因此这里应该将cur初始化为指向头结点(_dummyHead),然后利用count=_size;while(count--) cur=cur->next;或者 while(cur->next) cur=cur->next;循环(但是第二个方法好像更容易想到一点),这样循环结束时,就能保证了cur最终指向的是最后一个结点,当链表为空链表时也同样适用。
(3)对于addAtIndex函数,前面addAtTail函数找插入点的方法是这里找插入点方法的一种特殊情况,这里要在第index前插入节点,也就是要cur指针最终停在第index-1个结点,即初始化cur指针指向_dummyHead,然后进行循环,即LinkedNode* cur=_dummyHead; while(index--) cur=cur->next;,而前面addAtTail函数,就是这里的Index=_size.
(4)deleteAtIndex函数与addAtIndex函数找插入点的方法 完全一致。

最后总结一下:
1.addAtTail、addAtIndex、deleteAtIndex三个函数中寻找插入点的方法是一致的,都是让cur指针最终停在第index-1个结点,即初始化cur指针指向_dummyHead,然后进行循环,即LinkedNode* cur=_dummyHead; while(index--) cur=cur->next;,对于addAtTail函数,也就是把index换成了_size,但是更容易想到的方法是while(cur->next) cur=cur->next;
2.对于get函数,因为不涉及增加或删除元素,因此不像上面一样初始化cur指针指向头结点,而是指向第一个结点,再利用while(index--) cur=cur->next;就能够让cur最终指向第index个结点,其实这两种方法的循环条件都是while(index--) cur=cur->next;,唯一不同的是get函数cur指针初始化指向第一个结点,所以最终cur指向第index个结点,而addAtTail、addAtIndex、deleteAtIndex三个函数cur指针初始化指向头结点,即相比get函数的cur指针前移了一个结点,因此最终cur指向的结点也前移一个,指向了第index-1个结点

2.反转链表
在这里插入图片描述
思路:迭代法(双指针法)其实只要注意下面几点:
(1)开始先初始化cur指针指向头结点,pre指针为nullptr
(2)注意循环条件是while(cur),即cur指向空时循环停止
(3)循环内部即指针的移动就是让cur->next指向pre,即指针反转,但是需要先保存cur->next的值,否则无法cur就无法后移了。

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

3.两两交换链表中的结点
在这里插入图片描述

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead=new ListNode();
        dummyHead->next=head;
        ListNode* cur=dummyHead;
        while(cur->next!=nullptr&&cur->next->next!=nullptr) {
            ListNode* tmp1=cur->next;
            ListNode* tmp2=cur->next->next->next;
            cur->next=cur->next->next;
            cur->next->next=tmp1;
            tmp1->next=tmp2;
            cur=cur->next->next;
        }
        return dummyHead->next;


    }
};

思路:
首先要弄清cur指针指向的元素,cur指针被初始化为虚拟头结点,始终在被交换位置的两个结点的前一个结点,循环的终止条件就是cur指针后没有结点了,或者只有一个结点了,对应的判断语句就是cur->next!=nullptr&&cur->next->next!=nullptr
其次指针的指向变换可以看下面这张图,让dummyHead指向节点2,节点2指向节点1,节点1指向节点3,让节点间的指针捋顺之后就可以看到节点1,2被反转过来了,但是要注意的是当dummyHead指向节点2后,节点1变成了一个孤节点了,没有指针可以指向它的位置,因此需要提前创建tmp1指针指向节点1,节点3同理。最后要记得cur指针后移两个结点,即cur=cur->next->next
在这里插入图片描述

4.删除链表的倒数第N个结点
在这里插入图片描述

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead=new ListNode(0,head);
        ListNode* fast=dummyHead;
        ListNode* low=dummyHead;
        n++;
        while(n--)  fast=fast->next;
        while(fast!=nullptr){
            fast=fast->next;
            low=low->next;
        }
        ListNode* tmp=low->next;
        low->next=low->next->next;
        delete tmp;
        return dummyHead->next;
    }
};

思路:其实就是采用双指针算法,fast指针先移动n+1位,为什么移动n+1位是因为要删除倒数第n位,low指针就要指向倒数第n位的前一位,即倒数第n+1位,而low,fast指针同时移动的终止条件是while(fast!=nullptr),即最终fast指向最后结点的下一个结点,如果fast是先移动n位,那么最终low就会停在倒数第n位,而ast先移动n+1位的话,low就会停在倒数第n位的前一位。

5.链表相交
在这里插入图片描述
思路:这道题并不难,只要记住几个点:
1.首先要将两个链表尾部对齐,则计算两个链表长度之差,更长的链表指针先后移长度之差个结点。
2.两链表尾部对齐后再同时移动curA、curB指针,直到两指针相等或为空。
3.记得使用swap函数可以简化代码,swap用于交换两个对象的值.让headA始终指向长的那一条链表,可以减少后面的判断语句。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int length_A=0,length_B=0;
        if(headA==nullptr || headB==nullptr)    return NULL;
        length_A=count_length(headA);
        length_B=count_length(headB);
        if(length_B>length_A){
            swap(length_A,length_B);
            swap(headA,headB);
        }
        ListNode* curA=headA;
        ListNode* curB=headB;
        int move=length_A-length_B;
        while(move--) curA=curA->next;
        while(curA!=nullptr){
            if(curA==curB)  return curA;
            curA=curA->next;
            curB=curB->next;
        }
        return NULL;
        // while((curA!=curB)&&(curA!=nullptr)&&(curB!=nullptr)) {
        //     curA=curA->next;
        //     curB=curB->next;
        // }
        // if(curA==nullptr) return NULL;
        // return curA;

    }

    int count_length(ListNode *head){
        int length=0;
        while(head!=nullptr){
            length++;
            head=head->next;
        }
        return length;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值