代码随想录第3天|C++|链表|leetcode|203.移除链表元素|707.设计链表|206.反转链表

第二章 链表part01

强烈要求leetcode官方在链表题目上写清楚有没有头结点,有的题有有的题没,2题debug一直内存泄漏,原来有头结点📕
用时较长,希望下次快一点(o( ̄▽ ̄)ブ)

链表的基础知识

链表的定义

/**
 * 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) {}
 * };
 */
// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

基本操作复杂度分析
在这里插入图片描述

LeetCode 203.移除链表元素Easy

题目链接203. 移除链表元素

思路:本题是移除无头结点链表中所有指定val大小的元素,有两种思路(有无头结点都可使用1或2思路)

1是通过创建临时变量temp存储将要删除的元素

2是通过两个指针p,q动态移动,删除指定元素

难点:由于无头结点,需要分开考虑最前面head为val和一般情况下中间值为val两种情况,以1思路为例:处理头指针时,当当前轮次前面head不为空为val时才能删除head;处理中间值时,head位置已经确定,设current为head,若head后还有值(即current!=NULL&&current->next!=NULL),方可继续进行判断删除,否则直接不进循环return。

完整C++代码如下

在这里插入图片描述

//无头结点,使用1思路
//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //处理头指针为空情况
        if(head==NULL)return NULL;
        //目的:删除头部所有值为val的节点,确定head位置
        while(head!=NULL&&head->val==val){
            ListNode *temp=head;//临时变量存储将要删除的head
            head=head->next;
            delete temp;
        }
        ListNode* current=head;//此时head位置确定,是否为空不确定,但head上绝不可能为目标val
        //有0个或1个值都是直接结束,2个以上进入循环
        while(current!=NULL&&current->next!=NULL){
            if(current->next->val==val){
                ListNode *temp=current->next;
                current->next=current->next->next;
                delete temp;
            }else{
                current=current->next;
            } 
        }
        return head;
    }
};

在这里插入图片描述

//有头结点,使用2思路
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if(head==NULL)return NULL;
		ListNode*p=head;
        ListNode*q=p->next;
        while(q){
            if(q->val==val){
                q=q->next;
                delete p->next;
                p->next=q;
            }else{
                p=p->next;
                q=q->next;
            } 
        }
        return head;
    }
};

LeetCode 707.设计链表

题目链接707. 设计链表

思路:一些基本的链表操作

有头结点注意

  1. 构造函数没什么说的,注意格式MyLinkedList() : dummy_Head(new LinkedNode(0)), len(0) {}的学习
  2. 链表参数有两个,头指针(dummy_Head)指向了头结点(一般头结点的val为无意义,此处设为0)和链表长度(len)
  3. 由于头结点的存在,在addAtIndex函数和deleteAtIndex函数中可以很舒服的不用考虑首元结点(index为0)没有前驱的情况

:题目有头结点,默认val为0
在这里插入图片描述

完整C++代码如下

struct LinkedNode
{
    int val;
    LinkedNode *next;
    LinkedNode(int val) : val(val), next(nullptr) {}
};
class MyLinkedList
{
public:
    LinkedNode *dummy_Head;
    int len;

    MyLinkedList() : dummy_Head(new LinkedNode(0)), len(0) {}

    int get(int index)
    {
        if (len < index + 1 || index < 0)
            return -1;
        LinkedNode *p = dummy_Head->next;
        while (index--)
        {
            p = p->next;
        }
        return p->val;
    }

    void addAtHead(int val)
    {

        LinkedNode *Add_Head = new LinkedNode(val);
        Add_Head->next = dummy_Head->next;
        dummy_Head->next= Add_Head;
        len++;
    }

    void addAtTail(int val)
    {
        LinkedNode *Add_Tail = new LinkedNode(val);

        LinkedNode *p = dummy_Head;
        while (p->next)
        {
            p = p->next;
        }
        p->next = Add_Tail;
        len++;
    }

    void addAtIndex(int index, int val)
    {   
        if(index<0||index>len)
            return;
        LinkedNode *p = dummy_Head;
        LinkedNode *Add_Node = new LinkedNode(val);
        while (index--)
        {
            p = p->next;
        }
        Add_Node->next = p->next;
        p->next = Add_Node;
        len++;
        
    }

    void deleteAtIndex(int index)
    {

        if (index >= len || index < 0)
            return;
        
        LinkedNode *current = dummy_Head;
        while (index--)
        {
            current = current->next;
        }
        LinkedNode *temp = current->next;
        current->next = temp->next;
        delete temp;
        len--;
        temp = nullptr;
    }
};

补充:

  1. 构造函数的作用:

    • 给创建的对象建立一个标识符

    • 为对象数据成员开辟内存空间;

    • 完成对象数据成员的初始化。

LeetCode 206.反转链表

题目链接206. 反转链表

思路

本题链表没有头结点

  1. 顺序逆置链表,通过设置一个指针q来遍历链表,每轮让临时变量temp=q,q后移,而temp指向前一个head,完成操作后head后移,从而在head和q的不断后移中完成对链表的逆置,结束时head恰好指向最后一个位置,而q指向nullptr,完成逆置。

    在这里插入图片描述

    1. 递归,使用递归法遍历链表,当越过尾节点后终止递归,在回溯时修改各节点的 next 引用指向

完整C++代码如下

//1
//时间复杂度:O(N)
//空间复杂度:O(1)
class Solution
  {
  public:
      ListNode *reverseList(ListNode *head)
      {
          if (head == nullptr || head->next == nullptr)
              return head;
          ListNode *q = head->next;
          head->next = nullptr;
          while(q){
              ListNode *temp = q;
              q = q->next;
              temp->next = head;
              head = temp;
          }
          return head;
      }
  };
//2
//时间复杂度:O(N)
//空间复杂度:O(N)
class Solution
  {
  public:
      ListNode *reverseList(ListNode *head)
      {
		return recur(head,nullptr);
      }
  private:
    ListNode* recur(ListNode* cur,ListNode* pre){
            if(cur==nullptr)return pre;
            ListNode*res=recur(cur->next,cur);//不断递归直到cur->next为空,此时确定cur为最后一个结点(也即res)
            cur->next=pre;//回溯过程中不断修改方向,最后pre回到最上层,即开始设立的nullptr
            return res;
        }
  };
  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值