力扣刷题录——链表

一、移除链表元素

移除链表元素

法一:不使用虚拟头节点

    ListNode* removeElements(ListNode* head, int val) {
    
   //若删除头节点
    while(head!=NULL&&head->val==val)//连续删除头节点的条件
    {
     head=head->next;
    } 
    
    //删除其他节点(先判断是不是空链表)
    if(head!=NULL){

    ListNode* cur=head;
    while(cur->next!=NULL){
        if(cur->next->val==val)
        {cur->next=cur->next->next;}
        else
        {cur=cur->next;}
    }

    }
    return head;
    }

法二:使用虚拟头节点

  ListNode* dummy=new ListNode(0,head); //创建虚拟头节点并连接到原链表

    ListNode* cur=dummy; //用来遍历的指针
    while(cur->next!=NULL){
        if(cur->next->val==val)
        {cur->next=cur->next->next;}
        else
        {cur=cur->next;}
    }
    return dummy->next;
    

 二、设计链表

设计链表

单链表:

//先定义节点结构体
struct LinkNode{
int val;
LinkNode* next;
LinkNode(int val=0,LinkNode* next=NULL):val(val),next(next){}
};

class MyLinkedList {
    int size; //链表的长度 
    LinkNode* dummy; //虚拟头节点
public:
    MyLinkedList() {
     //初始化链表:长度为0,初始化虚拟头节点
     size=0;
     dummy=new LinkNode();
    }

    // 析构函数,释放所有节点的内存
    ~MyLinkedList() {
    LinkNode* cur = dummy;
    while (cur != nullptr) {
        LinkNode* temp = cur;
        cur = cur->next;
        delete temp; // 不断删除头节点,手动释放内存
    }
    
    }
    int get(int index) {
      //先判断index是否合理
      if(index<0||index>size-1)
      return -1;
      else{
        LinkNode* cur=dummy;
        int loop=index+1;
        while(loop--)
        {
            cur=cur->next;
        }
        return cur->val;
      }
    }
    
    void addAtHead(int val) {
      //先新建节点
      LinkNode* newNode=new LinkNode(val);
      //插入
      newNode->next=dummy->next;
      dummy->next=newNode;
      size++;
    }
    
    void addAtTail(int val) {
     LinkNode* newNode=new LinkNode(val);
     LinkNode* cur=dummy;
     while(cur->next!=NULL){
        cur=cur->next;
     }
     cur->next=newNode;
     size++;
    }
    
    void addAtIndex(int index, int val) {
      //先判断index是否合理
      if(index<0||index>size)
      return;

      LinkNode* newNode=new LinkNode(val);
      LinkNode* cur=dummy;
      int loop=index;
      while(loop--)
      {cur=cur->next;}
      newNode->next=cur->next;
      cur->next=newNode;
      size++;
    }
    
    void deleteAtIndex(int index) {
      //先判断index是否合理
      if(index<0||index>size-1)
      return;
      int loop=index; //让cur指向下标为index-1的节点
      LinkNode* cur=dummy;
      while(loop--){
        cur=cur->next;
      }
      cur->next=cur->next->next;
      size--;
    }
};

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

三、反转链表 

反转链表

 法一:逐个逆转方向

ListNode* reverseList(ListNode* head) {
     //法一:逐个逆转方向
     ListNode*cur=head,*pre=NULL,*temp;
     while(cur)
     {
        temp=cur->next; //一存
        cur->next=pre; //二改
        pre=cur; //三移
        cur=temp;
     }
     return pre;
    }

递归写法:

//递归写法
    ListNode* reverse(ListNode*cur,ListNode*pre){
        if(cur==NULL) //终止条件
          return pre; 
        ListNode* temp=cur->next; //先存
        cur->next=pre; //后改向
        return reverse(temp,cur); //进入下一轮逆转(将指针移动放进递归参数变化中)
    }
    ListNode* reverseList(ListNode* head) {
       return reverse(head,NULL); //调用递归
    }

 法二:虚拟头节点+头插法

    ListNode* reverseList(ListNode* head) {
     //法二:虚拟头节点+头插法
     ListNode*nummy=new ListNode();
     ListNode*cur=head,*temp;
     while(cur)
     {
        temp=cur->next; //一存
        cur->next=nummy->next; //二头插
        nummy->next=cur;
        cur=temp; //三移
     }
     return nummy->next;
    }

四、两两交换链表中的节点 

两两交换链表中的节点 

法一:

 ListNode* swapPairs(ListNode* head) {
     //借用虚拟头节点,1+2的模式交换
     ListNode*dummy=new ListNode(0,head);
     ListNode*cur=dummy;
     while(cur->next!=NULL&&cur->next->next!=NULL) //节点数为偶数或奇数时的循环条件(注意cur->next要写在前面,否则可能空指针异常)
     {
       //交换两个节点
       ListNode *temp=cur->next;//先保存一个节点,防止丢失(也可以借助两个临时指针存储信息,不容易错乱)
       cur->next=cur->next->next; //交换节点(三条线)
       temp->next=cur->next->next;
       cur->next->next=temp;
       cur=cur->next->next; //指针移动
     }
     return dummy->next;
    }

法二:递归法

五、删除链表的倒数第N个节点

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

法一:利用快慢指针

    ListNode* removeNthFromEnd(ListNode* head, int n) {
      //利用快慢指针的差值:n+1步;利用虚拟头指针,统一删除操作
      ListNode *dummy=new ListNode(0,head);
      ListNode*fast=dummy,*slow=dummy;
      //快指针先走n+1步
      for(int i=0;i<n+1;i++)
      {
        fast=fast->next;
      }
      //快慢指针再同时走,直至fast走到末尾
      while(fast)
      {
        slow=slow->next;
        fast=fast->next;
      }
      //删除节点
      slow->next=slow->next->next;
      return dummy->next;
    }

 法二:先计算出链表长度

int getLength(ListNode*head){
        int length=0;
        while(head){
            length++;
            head=head->next;
        }
        return length;
    }

    ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode*dummy=new ListNode(0,head); //利用虚拟头节点,统一删除操作
    ListNode*cur=dummy;
    //先计算出链表长度
    int lenght=getLength(head);
    //再找要删除节点的前一个节点(转换成顺数第几个节点)最后一位:正序lenght,逆序1 所以逆序第n位,对应正序第lenght+1-n位
    for(int i=0;i<lenght-n;i++) //cur走length-n步到达被删节点的前一个节点
    {
      cur=cur->next;
    }
    //最后删除节点
    cur->next=cur->next->next;
    return dummy->next;
    }

六、环形链表 

环形链表 

快慢指针:快指针速度为2,慢指针速度为1,若两个指针相遇则说明链表有环

       (快指针比慢指针快即可,但是2:1是最高效的)

双指针:index1从头节点出发,index2从相遇节点出发,则两者的相遇点在入环节点

 ListNode *detectCycle(ListNode *head) {
        //若快慢指针相遇,则说明有环
        ListNode*fast=head,*slow=head;
        while(fast!=NULL&&fast->next!=NULL) //让快慢指针跑起来,结束条件是fast没到末尾(因为fast一下跳两步,所以还要保证fast->next不为空)
        {
         fast=fast->next->next;
         slow=slow->next;
         if(slow==fast) //若相遇,则说明有环
         {
            ListNode*index1=head,*index2=fast; //从出发点和相遇点各派出速度同为1的指针,则两者相遇点在入环节点
            while(index1!=index2) //让两个指针跑起来,结束条件是index1==index2
            {
                index1=index1->next;
                index2=index2->next;
            }
            return index1;
         }
        }
        return NULL; //循环结束无环,返回null
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值