代码随想录算法训练营第三天 | 203.移除链表元素,707.设计链表 206.反转链表

203.移除链表元素

https://leetcode.cn/problems/remove-linked-list-elements/description/

1.不带表头法

        因为是不带表头的,所以要区分两种情况,第一种是要删除的链表元素就是表头的元素,这里假设有多个要删除的元素,所以应该是while(head!=NULL&&head->val==val)用的是while循环的方式,而不是If的形式,只要head的值等于val,那么head就不断往后移动;第二种是要删除的元素不是表头的元素,那么这时候只要让cur的指针移动到要删除元素的头一个节点,temp=cur->next(temp代表要删除的节点),cur->next=temp->next,就可以实现删除的效果。

        注意,在判断完第一种条件后,还需要判断head是否为空才可以直接进入下一种情况,这时候下一种情况的判断条件是while(cur->next!=NULL)。如果判断head是否为空,那判断条件就要写成while(head!=NULL&&head->next!=NULL)。循环完,要记得返回head节点。

2.带表头结点法

        这种方法要求我们自己先设置一个表头结点dummyHead,dummyHead->next=head,用这种方法主要是为了方便统一,如果用这种方法,就不需要判断不带表头法所需要的两种情况,因为有了咱们自己定义的表头结点,其他所有要删除的元素都属于带表头法的第二种情况了。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
    //不带头结点法
    // ListNode*temp1;
    // while(head!=NULL&&head->val==val)
    // {   temp1=head;
    //     head=head->next;
    //     delete temp1;
    // }
    // if (head==NULL) return head;
    // ListNode*cur=head;
    // ListNode*temp2;
    // while(cur->next!=NULL)
    // {
    //     if(cur->next->val==val)
    //     {
    //         temp2=cur->next;
    //         cur->next=temp2->next;
    //         delete temp2;
    //     }
    //     else
    //     {
    //         cur=cur->next;
    //     }
    // }
    // return head;
    //带头结点法
    ListNode*dummyHead=new ListNode(0);
    dummyHead->next=head;
    ListNode*cur=dummyHead;
    while(cur->next!=NULL)
    {
        if(cur->next->val==val)
        {
            ListNode*temp=cur->next;
            cur->next=temp->next;
            delete temp;
        }
        else
        {
            cur=cur->next;
        }
    }
    head=dummyHead->next;
    delete dummyHead;
    return head;
    }
};

707.设计链表

1.首先自定义LinkedNode以及初始化链表

        初始化链表的时候我们用的是带表头结点的方法,方便后序的统一。同时,要将size设置为0.

2.Get函数

        通过传入参数Index,index表示第index个节点(注意,是从节点0开始的),要找到对应的元素值,首先要对index进行判断,如果indez<0||index>size(因为是从节点0开始的,所以应该是>size),return -1(表示找不到);如果index合法,就设置cur=dummyHead->next,(这里设置为->next是让它直接指向第0个节点,因为咱们是根据index的值判断的,index=0表示移动0次,那么这时候跟我们设置的就符合,然后如果index=1,就在原来的基础上向右移动一位,依此类推。

3.addAtHead函数

        通过传入参数val表示要插入的节点的值,这是一个从表头插入的方法,所以直接new一个节点newNode,newNode->next=dummyHead->next;dummyHead->next=newNode即可。

4.addAtTail函数

        通过传入参数val表示要插入的节点的值,然后找到链表的最后一个节点,在节点后面添加值为val的节点,具体是设置cur=dummyHead(这里不设置为head->next是因为咱们要找的是插入位置的前一个节点而不是插入位置),while(cur->next!=NULL),cur就会不断移动直到cur->next==NULL,这时候的cur就是末尾的节点。

 5.deleteAtIndex函数

        这个跟Get函数很像但有区别,Get函数是找index位置的值,而deleteAtIndex则是删除index位置的节点,所以Get的初始化是cur=dummyHead->next;while(index--);而deleteAtIndex则是初始化cur=dummyHead;while(index--),因为我们要找的是delete掉的节点的前一个节点,这样才能删除要被删除的节点。同时也要注意判断index是否合法。

6.printLinkedList函数

        其实就是让指针从真正有值的第一个节点开始(也就是dummyHead的下一个节点)移动到最后一个节点,输出值即可。

class MyLinkedList {
public:
  
    MyLinkedList() {
       dummyHead=new LinkedNode(0);
       size=0;
    }
    
    int get(int index) {
        if(index<0||index>=size)
        {
            return -1;
        }
        LinkedNode*cur=dummyHead->next;
        while(index)
        {
            cur=cur->next;
           index--;
        }
        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;
        while(cur->next!=NULL)
        {
            cur=cur->next;
        }
        LinkedNode*newNode=new LinkedNode(val);
        cur->next=newNode;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index>size) return;
        if(index<0) index=0;
        LinkedNode*cur=dummyHead;
        while(index)
        {
            cur=cur->next;
            index--;
        }
        LinkedNode*newNode=new LinkedNode(val);
        newNode->next=cur->next;
        cur->next=newNode;
        size++;
    }
    
    void deleteAtIndex(int index) {
        if(index<0||index>=size)
             return;
        LinkedNode*cur=dummyHead;
        while(index--)
        {
            cur=cur->next;
        }
        LinkedNode*temp=cur->next;
        cur->next=temp->next;
        delete temp;
        temp=NULL;
        size--;
    }
private:
    LinkedNode*dummyHead;
    int size;
};

206反转链表

https://leetcode.cn/problems/reverse-linked-list/submissions/495429721/

1.双指针法

        定义一个pre指针,注意pre指针初始化是NULL,因为第一个节点反转的话,指向的节点是空的,定义一个cur指针,让cur->next=pre,然后让pre和cur都往后移动,循环让cur->next=pre即可。注意在这个过程中还要设置一个临时指针变量来存储cur->next,这样cur才能移动到下一个位置,不然cur->next=pre这一步会使cur丢失掉它原本指向的下一个位置。

2.递归法1

         递归法的第一种和双指针法的思路是差不多的,通过传入参数pre,cur,然后tmp=cur->next,cur->next=pre,然后不断调用该函数,下一次函数传入的值的pre是现在执行的这个函数的cur,传入的cur的值是现在执行函数的tmp,不断调用直到cur==NULL为止。

3.递归法2

        递归法2是先走到最后一个节点,然后再调整,而递归法1是先调整,再走到最后一个节点。递归法2是一上来就调用reverseList,直到到达最后一个节点,再从最后一个节点的前一个节点开始反转,直到走回到链表原本的头结点。

class Solution {
public:
    ListNode*reverse(ListNode*pre,ListNode*cur)
    {
        if(cur==NULL)
        return pre;
        ListNode*temp=cur->next;
        cur->next=pre;
        return reverse(cur,temp);
    }
    ListNode* reverseList(ListNode* head) {
    //非递归
    //     ListNode*pre=NULL;
    //     ListNode*cur=head;
    //     while(cur)
    //     {
    //         ListNode*tmp=cur->next;
    //         cur->next=pre;
    //         pre=cur;
    //         cur=tmp;
    //     }
    //     return pre;
    // }
    //递归1
    // if(head==NULL||head->next==NULL)
    //     return head;
    // ListNode*newHead=reverseList(head->next);
    // head->next->next=head;
    // head->next=NULL;
    // return newHead;
    // }
    //递归二
    return reverse(0,head);
    }
};

你可能感兴趣的:(算法,链表,数据结构)