链表部分小题和双向链表

1. 环形链表(经典中的经典),返回入环节点,那么我们应该怎么做呢,首先判断链表有没有环,然后是不是空,用经典的快慢指针,快的指针一次走两步,慢的指针走一步,

问题一:先想一下,为什么fast的速度设置为2,slow的速度为1

假如两个有环,他们俩个一定会相遇,因为在环中,fast相当于比slow永远多走一步,也就是说,fast相当于在环里面一直走,slow一直保持原有的位置没有动,所以一定会相遇,所以fast的速度为2在环中会一定和slow相遇

问题二后面的代码是什么意思(不明白看我的图)

fast的速度一直是slow的二倍,所以肯定路程也是二倍(保姆级教学

L是头到环入口的距离,环入口到相遇点的距离是X,M是相遇点到环的入口的距离

力扣142

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow =head;
        ListNode cur =head;
        if(head==null){                     //判断是否为空
            return null;
        }
        
        while(fast!=null&&fast.next!=null){//如果没有环,那么一定会有空的时候
            fast=fast.next.next;
            slow=slow.next;
            if(slow==fast){             //把它放后面很细节,是为了不让fast和slow等于头退出
                break;
            }
        }
        if(fast==null||fast.next==null){    //判断是否有环
            return null;
        }
        while(slow!=cur){                   //找环的入口点
            cur=cur.next;
            slow=slow.next;
        }

        return cur;

2.链表相交   很简单思路,把A,B链表走一遍,知道长度差,然后谁长,让谁先走,然后看相不相交

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode cur=headA;
        ListNode curv=headB;
        int la=0;                            //a表长度
        int lb=0;                            //b表长度
        if(headB==null&&headA==null){
            return null;
        }
        if(headA==null&&headB!=null||headB==null&&headA!=null){
            return null;
        }
        while(cur!=null){                    //计算A与B的长度
            la++;
            cur=cur.next;
        }
        while(curv!=null){
             lb++;
             curv=curv.next;
        }
        cur=headA;                           //还原两个指针,让他们两个再次指向头
        curv=headB; 
        if(lb>la){
          while(lb-la>0&&curv!=null){      //b长先走   
             curv=curv.next;
             lb--;
            }
        }
        else{
          while(la-lb>0&&cur!=null){
             cur=cur.next;                //a长a先走
             la--;
            }
        }
        while(cur!=null){                     //很重要一个点,相交是点相同,不是点值相同
            if(cur==curv){                    //不要去写.val==.val是不对的
                return cur;
            }
            cur=cur.next;
            curv=curv.next;
            }

            return null;
        }
    }

3.双向链表。要求会写,这是类的必须,其他类中的方法放到下面,内部类是必须要的,然后下面是链表具备的头和尾指针方便插入和删除,(需要分到两个部分写)

下面的各种函数你也都可以用phead就是像c语言那种传一个头之类的。

public class ListNode {
    public class LinkedNode{
        int val;
        LinkedNode next = null;
        LinkedNode prev=null;
        LinkedNode(int val) {
            this.val = val;
        }
}
       public  LinkedNode head;            //链表的头
       public  LinkedNode tail;            //链表的尾巴

3.(1)头插

 // 2、无头双向链表实现
        //头插法
        public void addFirst(int data){
            LinkedNode p=new LinkedNode(data);  申请一个节点
            if(head==null){        //之前的节点为空的话,就头和尾都在开始的节点
                head=p;
                tail=p;
            }
            p.prev=null;          //头节点的前面是NULL
            head.prev=p;          //头连接P节点
            p.next=head;        
            head=p;               //P成为新的头
            tail.next=null;       //尾节点下一个还是null
        }

(2)尾插

 public void addLast(int data){
            LinkedNode p=new LinkedNode(data);    //还是生成个节点
            if(head==null){
                head=p;                           //头和尾都是空
                tail=p;
            }
            while(tail.next!=null){
                tail=tail.next;                  //尾巴遍历到最后
            }
            tail.next=p;                         //tail的下一个连像尾巴节点p
            p.prev=tail;                         //p的前一个节点是尾巴
            tail=p;                              //尾巴指向p
            }
(3)任意位置插入,第一个数据节点为0号下标,插入节点
 public boolean addIndex(int index,int data) {
           if(index<0||index>size()){               //插入序列不合理
               return false;
           }
           LinkedNode cur=head;
           LinkedNode p=new LinkedNode(data);
           int n=1;
           if(index==1){                          //插入第一个就是头插
               addFirst(data);
           }
           while(n<index){
               n++;                              //找到要插入节点的前面
               cur=cur.next;
           }
           if(cur.next.next!=null) {
               p.next=cur.next;                 //插入中间节点
               p.prev=cur;                      //P的前驱后继
               cur.next.prev=p;                  
               cur.next=p;                      //前驱节点的下一个连接他
           }
           else {
               addLast(data);                  //最后一个就是尾插
           }
           return true;
        }

(4)看关键字key在不在链表中(简单的遍历)

 //查找是否包含关键字key是否在单链表当中
        public boolean contains(int key){
            LinkedNode cur=head;
            while(cur!=null){
               if(cur.val==key){
                   return true;
               }
               cur=cur.next;
           }
           return false;
        }
(5)//删除第一次出现关键字为key的节点
//删除第一次出现关键字为key的节点
        public void remove(int key){
            LinkedNode cur=head;
            while(cur!=null){
                if(cur.next.val==key){
                    break;
                }
            }
            cur.next.prev=null;       //key值的前一个点,的前指针为空
            cur.next.next.prev=cur;   //key的后一个节点连key前面的节点
            cur.next=cur.next.next;   //key值的前一个点下一个连接key值的下一个
        }

(6)删除所有值为key的节点(删除全部和上面的删除一个意思一样)

 public void removeAllKey(int key){
            LinkedNode cur=head;
            while(cur!=null){
              if(cur.next.val==key){
                  cur.next.prev=null;
                  cur.next.next.prev=cur;
                  cur.next=cur.next.next;
               }
           }
        }

(7)链表长度和展示(简单不解析了)

  //得到单链表的长度
        public int size(){
            LinkedNode cur=head;
            int n=0;
            while(cur!=null){
                cur=cur.next;
                n++;
            }
            return n;
        }
         public void display(){
            LinkedNode cur=head;
            while(cur!=null){
                System.out.println(cur.val);
                cur=cur.next;
            }
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗哥不是甜妹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值