当前位置: 代码网 > it编程>软件设计>算法 > 五道LeetCode《中等难度》的单链表题

五道LeetCode《中等难度》的单链表题

2024年08月06日 算法 我要评论
图文并茂,五道单链表题,看明白并且能独自实现,你就初步掌握链表了

1. 剑指 offer ii 021. 删除链表的倒数第 n 个结点

在这里插入图片描述
题目描述:

三种解法:

第一种解法(单指针):

在这里插入图片描述

代码如下:

class solution {
    public listnode removenthfromend(listnode head, int n) {
    			
        listnode dummy = new listnode(0, head);//设置哨兵位
        int length = getlength(head);//求出链表长度
        listnode cur = dummy;//用cur去遍历
        //遍历l-n+1次就是要删除结点的前驱结点
        for (int i = 1; i < length - n + 1; ++i) {
            cur = cur.next;
        }
        //前驱结点的next指向要删除结点的后一个结点
        cur.next = cur.next.next;
        return dummy.next;
    }
		//求出链表长度
    public int getlength(listnode head) {
        int length = 0;
        while (head != null) {
            ++length;
            head = head.next;
        }
        return length;
    }
}

作者总结:

复杂度分析:

第二种解法(栈):

实现思路:

具体实现:

如图:

在这里插入图片描述

代码如下:

class solution {
    public listnode removenthfromend(listnode head, int n) {
        listnode dummy = new listnode(0, head);//创建哨兵位
        deque<listnode> stack = new linkedlist<listnode>();//创建一个栈
        listnode cur = dummy;//cur代替哨兵位遍历
        while (cur != null) {
        //依次放入
            stack.push(cur);
            cur = cur.next;
        }
        //弹出倒数n个结点
        for (int i = 0; i < n; ++i) {
            stack.pop();
        }
        //当前栈顶就是要删除结点的前驱结点
        listnode prev = stack.peek();
        //
        prev.next = prev.next.next;
        return dummy.next;
    }
}

作者总结:

复杂度分析:

第三种解法(双指针):

解题思路:

具体实现:

如图:
在这里插入图片描述
代码如下:

class solution {
    public listnode removenthfromend(listnode head, int n) {
    //判断是否为空
        if(head==null) {
            return head;
        }
        //创建一个哨兵位
        listnode newhead=new listnode(0);
        //哨兵位的next指向head
        newhead.next=head;
        //将cur和prev同时指向newhead
        listnode cur=newhead;
        listnode prev=newhead;
		//快指针先走n+1步(也可以快指针总head走,走n步就可以,核心思路就是慢指针要和快指针之间的距离差1)
        for(int i=0;i<n+1;i++) {
            cur=cur.next;
        }
        //两个指针一起走
        while(cur!=null) {
            cur=cur.next;
            prev=prev.next;
        }
        //最后删除倒数第n个结点
        prev.next=prev.next.next;
        //返回newhead的next
        return newhead.next;
        
    }
}

作者总结:

复杂度分析:

2. 删除排序链表中的重复元素 ii(重点)

在这里插入图片描述

题目描述:

需要考虑的事项:

一种普通状态:

两种特殊状态:

普通状态

在这里插入图片描述

解题思路:

如图:

在这里插入图片描述

在这里插入图片描述

最后运行结果:

在这里插入图片描述

特殊状态(头结点重复时)

在这里插入图片描述

在这里插入图片描述

运行结果:

在这里插入图片描述

特殊状态(删除尾结点时)

在这里插入图片描述

在这里插入图片描述
解决之后运行结果:

在这里插入图片描述
具体代码如下:

class solution {
    public listnode deleteduplicates(listnode head) {
        if(head==null||head.next==null) {
            return head;
        }
        listnode prev=null;
        listnode cur=head;
        listnode curnext=cur.next;
        while(curnext!=null) {
            //当他们的值不同时,集体后移,注意顺序
            if(cur.val!=curnext.val) {
                prev=cur;
                cur=curnext;
                curnext=curnext.next;
            } else {
                //当他们的值相同时,并且curnext不为空,进入循环
                //注意要将curnext!=null的判断条件写在左边
                //逻辑运算&&,先判断左边,如果左边为真才判断右边,
                //当你的curnext!=null写在右边时,
                //他会先进行curnext.val的操作,此时你的curnext已经为空
                //再去访问就会发出空指针异常
                while(curnext!=null&&cur.val==curnext.val) {
                    curnext=curnext.next;
                }
                //判断prev是否为空,如果为空就是头删
                if(prev!=null) {
                    //不为空将prev的next指向curnext
                    prev.next=curnext;
                } else {
                    //为空则头节点变成curnext
                    head=curnext;
                }
                //后续过程不变
                cur=curnext;
                //判断curnext是否为空,如果为空则不进行该操作
                if(curnext!=null)
                curnext=curnext.next;
            }
        }
        return head;
    }
}

作者总结

复杂度分析:

3. 删除链表中的节点

在这里插入图片描述
题目描述:

解题思路:

如下图:
在这里插入图片描述

代码如下:

class solution {
    public void deletenode(listnode node) {
        node.val=node.next.val;//替换为下一个结点的val
        node.next=node.next.next;//替换为下一个结点的next
	}
}

总结:

复杂度分析:

4. 重排链表

在这里插入图片描述

题目描述:

大概意思就是:
在这里插入图片描述

解题思路:

思路一:

具体实现:

代码如下:

class solution {
    public void reorderlist(listnode head) {
        if(head==null||head.next==null) {
            return;
        }
        //利用顺序表存储,然后按指定位置
        //我这里没有直接使用库的顺序表,
        listnode [] array=new listnode[50000];
        listnode cur=head;//
        int i=0;
        //从0下标存入
        while(cur!=null) {
            array[i]=cur;
            cur=cur.next;
            i++;
        }
        //最后i是元素个数
        listnode newhead=new listnode(0);
        listnode newprev=newhead;
        int a=0;//a是下标
        int b=i-1;//b也是下标,i是元素个数,元素个数-1就是最后一个元素的下标
        int count=1;//根据奇偶判断读取哪个下标的元素
        //最后i+1就是链表的结点个数+1,
        //count是从1开始的,所以当count=i+1时,就代表读取完了所有结点
        while(count!=i+1) {
        //如果是奇数,就顺序读取
            if(count%2!=0) {
               newprev.next=array[a];
               newprev=newprev.next;
                a++;//
            } else{
            //如果是偶数就逆序读取
                 newprev.next=array[b];
                 newprev=newprev.next;
                 b--;
        }
        count++;
    }
    //将左后一个结点呢next置为kong,防止循环
       newprev.next=null;
       //将头节点改为newhead的next
        head=newhead.next;
    }
}

复杂度分析:

思路二(寻找链表中点 + 链表逆序 + 合并链表)

思路二:

如图:

在这里插入图片描述
注意:

具体步骤:

代码如下(注意注释)

class solution {

     public void reorderlist(listnode head) {
     if(head==null||head.next==null) {
             return;
         }
        //找到中间结点
        listnode prev=head;//慢指针
        listnode cur=head;//快指针
        while(cur!=null&&cur.next!=null) {
            cur=cur.next.next;
            prev=prev.next;
        }
        //逆序单链表
        cur=reverse(prev);
        prev=head;//prev从头遍历
        listnode newhead=new listnode(0);
       listnode newprev=newhead;
        int i=1;//来判断调用谁的结点
        while(true) {
            if(i%2!=0) {
               newprev.next=prev;//衔接该结点
             //当两个结点相等时退出循环
               if(prev==cur) {
               //并将newprev置为下一个结点
            		newprev=newprev.next;
                  	 break;
               }
               prev=prev.next;//prev指向下一个结点
            } else {
           	  newprev.next=cur;//衔接该结点
           	 //当两个结点相等时退出循环
           	 if(prev==cur) {
           	 //并将newprev置为下一个结点
           		newprev=newprev.next;
             	   break;
          	  }
            	cur=cur.next;//cur指向下一个结点
            }
            i++;
            newprev=newprev.next;//置为下一个结点
        }
        newprev.next=null;//将尾结点的next置为null,防止循环

     }
     //逆置链表函数
    public listnode reverse(listnode head) {

        listnode prev=null;
        listnode cur=head;
        while(cur!=null) {
        listnode curnext=cur.next;
        cur.next=prev;
        prev=cur;
        cur=curnext;
        }
        return prev;
    }

作者总结:

复杂度分析:

5. 剑指 offer ii 077. 链表排序(重点!)

在这里插入图片描述

题目描述:

解题思路:

如图:

在这里插入图片描述

  listnode cur=head.next;//后续链表的头指针
  
  listnode newhead=head;//当前有序链表的头指针
  
  newhead.next=null;//与后续链表断开联系
  
  listnode prev=newhead;//有序链表向后遍历指针的前驱指针
  
  listnode prevnext=newhead.next;//用于有序链表向后遍历的指listnode last=newhead;//尾结点
  
  listnode curnext=cur.next;//用于找回后续链表的指针

具体实现:

插入过程:
(有小瑕疵,cur跟尾结点比较的过程忽略了,直接按顺序对比去了,但是大体思路是这样)
在这里插入图片描述

代码如下:

class solution {
    public static listnode sortlist(listnode head) {
        if (head == null || head.next == null) {
             return head;
         }
         listnode cur=head.next;//后续链表的头节点
         listnode newhead=head;//当前有序链表的头节点
         newhead.next=null;//与后续链表断开联系
         listnode prevnext=newhead.next;//有序链表向后遍历的结点
         listnode prev=newhead;//有序链表向后遍历结点的前驱结点
         listnode last=newhead;//尾结点
         while(cur!=null) {
             //头插
             listnode curnext =cur.next;
             if(newhead.val>=cur.val) {
                 cur.next=newhead;
                 newhead=cur;
             } else if(last.val<cur.val) {
             		//尾插
                 last.next=cur;
                 last=cur;
                 last.next=null;
             } else {//中间插入
             //找到大于等于cur.val的结点
                while(cur.val>prevnext.val) {
                //prev一直保存prevnext的前一个结点
                    prev=prevnext;
                    //prevnext置为它的下一个结点
                    prevnext=prevnext.next;
                }
                //将cur插入prev和prevnext之间
                prev.next=cur;
                cur.next=prevnext;
             }
             //重置prev
             prev=newhead;
             //重置prevnext
             prevnext=prev.next;
             //重置cur
            cur=curnext;
         }
         //返回新头节点
    return newhead;
   } 
}

作者总结:

复杂度分析:

删除链表倒数第n个结点oj
删除链表中的重复结点ii
删除链表中的节点
重排链表
链表排序

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com