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

203.移除链表元素

203.移除链表元素

代码随想录(programmercral.com)

手把手带你学会操作链表 | LeetCode:203.移除链表元素

思路

从头节点出发,依次向后遍历,直到遍历到待删除元素的前驱节点时,即使用cur->next->val是否于target相同来对比是否找到待删除节点(为什么不使用cur->val来对比呢?原因是,如果发现当前所指节点为待删除节点的时候没办法删除,单链表要删除一个元素必须要其前驱),一直向后遍历,直到所有待删除元素全部删除为止。

代码实现:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *dummyhead =new ListNode(0);
        dummyhead->next=head;
        ListNode *p=dummyhead;
        while(p->next!=nullptr){
            if(p->next->val==val){
                ListNode *q=p->next;
                p->next=q->next;
                delete q;
            }
            //p=p->next;出错,这样会漏处理节点
            else p=p->next;
        }
        head=dummyhead->next;
        delete dummyhead;
        return head;

    }
};

时间复杂度为o(n) 单纯删除链表上的一个元素该操作的时间复杂度是o(1)但是由于链表没有随机访问的特性,因此对于只带头指针的单链表来说,找到特定的节点必须从头开始一个节点一个节点的遍历,该操作的时间复杂度为o(n) 因此总的时间复杂度为o(n) 未利用到额外的空间开销,空间复杂度为o(1);

此外,需要注意的是,这里所说的头节点和考研中所学的头节点是两个概念,这里的头节点是指链表的第一个节点,对应于考研中不带头节点的链表,这里所插入的虚拟头节点对应于考研中的头节点,此外掌握c++语法,如何新建一个节点,使用关键字new 例如ListNode *head = new ListNode(头节点的值)

707.设计链表

707.设计链表

代码随想录(programmercral.com)

帮你把链表操作学个通透!LeetCode:707.设计链表

思路:

本题就是实现一遍链表的一些基本操作,比较考验代码能力

代码实现:

class MyLinkedList {
public:
//比较容易 就是比较考验代码能力    
    struct LinkNode{
        int val;
        LinkNode *next;
        LinkNode(int val):val(val),next(nullptr){}
    };
    //初始化链表
    MyLinkedList() {
        _dummyhead=new LinkNode(0);
        _size=0;
    }
    //获取指定节点元素的值
    int get(int index) {
        //条件判断,判断index是否为合法值
        if(index>(_size-1)||index<0) return -1;
        LinkNode *p=_dummyhead;
        for(int i=0;i<=index;i++){
            p=p->next;
        }
        //while(index--) p=p->next;
        return p->val;
    }
    //在链表头插入节点
    void addAtHead(int val) {
        if(_size>1000) return;
        LinkNode *node=new LinkNode(val);
        node->next=_dummyhead->next;
        _dummyhead->next=node;
        _size++;
    }
    //在链表末尾插入节点
    void addAtTail(int val) {
        if(_size>1000)return;
        LinkNode *node = new LinkNode(val);
        LinkNode *p=_dummyhead;
        while(p->next!=nullptr){
            p=p->next;
        }
        node->next=nullptr;
        p->next=node;
        _size++;

    }
    //在指定位置插入节点
    void addAtIndex(int index, int val) {
        if(index>(_size)||index<0)return;
        LinkNode *node=new LinkNode(val);
        LinkNode *p=_dummyhead;
        int i;
        for(i=0;i<index;i++){
            p=p->next;
        }
        node->next=p->next;
        p->next=node;
        _size++;

    }
    //删除指定节点
    void deleteAtIndex(int index) {
        if(index>(_size-1)||index<0) return;
        LinkNode *p=_dummyhead;
        int i;

       for(i=0;i<index;i++) p=p->next;
        LinkNode *q=p->next;
        p->next=q->next;
        delete q;
        _size--;

    }
   /* void printLinkList(){
        LinkNode *p=_dummyhead;
        while()
    }*/
private:
    int _size;
    LinkNode *_dummyhead;
};

206.反转链表

206.反转链表

代码随想录(programmercral.com)

帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法

思路:

方法一:头插法

只需要使用头插法的性质即可,即创建的链表元素顺序是原来的逆序,并且只需要创建一个虚拟头节点来进行头插即可,不需要额外的空间

代码实现:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *dummyhead=new ListNode(0);
        dummyhead->next=nullptr;
        //头插法
        while(head!=nullptr){
            ListNode *p=head;
            head=head->next;
            p->next=dummyhead->next;
            dummyhead->next=p;
        }
        head=dummyhead->next;
        delete dummyhead;
        return head;
    }
};

时间复杂度为o(n)空间复杂度为o(1)

方法二:双指针法

只需要要改变链表next指针的指向,直接将链表反转,而不用重新定义一个新的链表,首先定义一个p指针指向头节点,再定义一个pre指针,初始化为null。然后开始反转,首先要把p->next节点用temp保存一下,否则把p的指向改变之后,后面的链表就找不到了,走丢了。然后把p->next指向pre,p向后走,pre向后走,直到p指向空,说明所有的元素都处理了一遍,整个链表反转完成,pre指向的就是新的头节点

代码实现:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //解法二 双指针法
        ListNode *temp;
        ListNode *p=head;
        ListNode *pre=nullptr;
        while(p!=nullptr){
            temp=p->next;
            p->next=pre;//改变链表指向
            pre=p;
            p=temp;//两个指针向后移动
        }
        return pre;
    }
};

时间复杂度 o(n)空间复杂度o(1)

方法三:递归

思路和双指针法相同,只不过写成了递归版本,把每次反转过程用一个递归处理。

代码实现:

class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur==nullptr) return pre;//对应双指针写法,当cur指向空说明所有节点都处理了一遍 返回pre
        ListNode *temp = cur->next;
        cur->next=pre;//改变指向
        return reverse(cur,temp);//相当cur和pre向后移动一位
        //这里要把pre一层一层的返回回去才对
    }
    ListNode* reverseList(ListNode* head) {
        //递归版本
        return reverse(nullptr,head);
    }
};

时间复杂度o(n) 空间复杂度o(n),因为每一个节点的反转过程用一个递归函数实现,一共有n个节点,所以会压入栈n个函数,空间复杂度为o(n);

总结

今天的算法题算是用代码把理论知识实践了一下,加强了对链表的认知,还不错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值