单链表习题

第一个圈    ListNode相当于之前的Node 一个引用类 到之后形成一个节点

第二个圈   定义了两个域 相当于之前的data和next

第三个是    一个构造方法 便于之后用 域

ListNode表示一个返回值 

1.移除链表元素

 代码如下:

public class Eriksenn{
    public class ListNode{
        int val;
        ListNode next;
        ListNode(int x){
            val=x;
        }
        class Soulution{
            //返回值类型为ListNode 为引用类型 应当返回指针引用类型
            public ListNode removeElements(ListNode head,int val){
                if(head==null){
                    return null;
                }
                //定义出两个要用的箭头标志 
                // 由于head已经由ListNode传入所以不能用养成习惯的this
                ListNode prev=head;
                ListNode cur=prev.next;
                
                while(cur!=null){
                    if(cur.val==val){
                        prev.next=cur.next;
                        cur=cur.next;
                    } else {
                      prev=cur;
                      cur=cur.next;
                    }
                    if(head.val==val){
                        head=head.next;
                    }
                    //返回值为引用类型 head指向也表示引用类型 
                    return head;
                }
            }
        }
    }
}

 2.反转链表

 

本题思路说难确实 要反转一个链表那就创三个引用对象指向

分别为 prev cur curNext

注意:

1.初始时与进行过程中 他们三个的相对位置关系是不变的

相对位置  第一位为prev  二 cur   三  curNext

2.在实现过程 注意先变化prev的位置关系 再去变化cur的 最后变化curNext、

值得一提的是在变化过程中  他们三个的相对位置一直是不发生变化的

代码如下

public class Eriksenn {
    public class ListNode{
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
        }
        public ListNode resevre(ListNode head,ListNode newHead) {

            //初始化时cur指向头 其他两个都可能是null 
            // 所以都初始化为null
            ListNode newhead=new ListNode(1);
            ListNode prev = null;
            ListNode cur = head;
            ListNode curNext = null;

            //为什么用cur做判断条件 
            // 因为curNext为空时还有元素没有搞好
            //有可能head一开始为空

            while (cur != null) {
                curNext = cur.next;
                if (curNext == null) {

                    //反转后的头就是cur
                    newHead = cur;

                }

                //举个例子当一开始时prev为null
                // cur指向头这一波下来直接把头的next给赋成null 进而继续
                cur.next = prev;

               
                //按照规律先变化prev 再cur 再上去变化curNext
                prev = cur;//prev往前移一个
                cur = cur.next;
                //只要cur不为null 那么继续往上变化curNext
            }

            return newhead;//返回新的头即可

        }
    }
}

3.链表的中间结点

 

 核心在其中

代码如下

public class Eriksenn {
    public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
        public ListNode findmid(ListNode head, ListNode newHead) {
           //给出两个指向 fast是slow移动的二倍
            ListNode slow=head;
            ListNode fast=head;

            if(head==null){
                return slow;
            }
            
            //不可调换位置 若先fast.next为空
            // 由于fast已经为空了
            // 然后fast.next空的空 则会空指针异常
            //这两种情况是根据总结点数是奇数或偶数给出的 自己画一下
            //记住核心 slow每次走一步 fast走两步
            while(fast!=null&&fast.next!=null){

                //fast走两步
                fast=fast.next.next;
                slow=slow.next;
            }
            return slow;
        }
    }
}

public class Eriksenn { 
    class Node{
        public  Node next;
        public Node head;
        public Node yidong(int k){
            Node fast=this.head;
            Node slow=this.head;
            while(k-1>0){
                if(fast.next!=null){
                    fast=fast.next;
                    k--;
                } else {
                    System.out.println("没有这个节点");
                }
            } 
            if(fast.next!=null){
                fast=fast.next;
                slow=slow.next;
            }
            return slow;
        }
    }
}

 

思路 如果选取一个数据data为12  首先开出两块空间 

那么根据题目要求得知 小于12的 放前面一块 大于12的 放后面一块

用尾插法进行放置

之后再把他俩块连在一起

 public Node part(int x){
            Node bs=null;
            Node be=null;
            Node as=null;
            Node ae=null;
            Node cur=this.head;
            while(cur!=null){
                //当原链表cur指向数据小于x 放到第一段
                if(cur.data<x){
                    //当第一次时 bs指向null
                    if(bs==null){
                        //bs be 都应该指向cur
                        bs=cur;
                        be=cur;
                        //如果bs不为空 那么用尾插法进行
                    } else {
                        be.next=cur;
                        be=be.next;
                    }
                    //cur指向data 大于x时 放到第二段
                } else {
                    //第一次时as指向null
                    if(as==null){
                        //as ae 都应该指向cur
                        as=cur;
                       ae=cur;
                    } else {
                        ae.next=cur;
                        ae=ae.next;
                    }
                }
                cur=cur.next;
            }
            //1.判断bs是否为空
            if(bs==null){
                return as;
            }
            //2.判断bs不为空 需要进行拼接
          be.next=as;
            //3.如果ae不为空 ae的next需要置为空
            if(ae!=null){
                ae.next=null;
            }
            //拼接之后返回bs
            return bs;
        }
    }
}

public Node leomessi(){
            //创建一个虚拟头来链接不重复的节点
            //默认为空的
            Node node=new Node(-1);//定义时随意给data值
            Node cur=this.head;
            Node tmp=node;
            while(cur!=null){
                //因为空的data取出来肯定会发生空的异常
                if(cur.next!=null&&cur.data==cur.next.data){
                    //由于连着重复的数据有可能不止有两个 定义一个while循环
                    while(cur.next!=null&&cur.data==cur.next.data){
                        cur=cur.next;
                    }
                    //当走到最后一个重复时 得多走一步
                    cur=cur.next;
                } else {
                    //为了不让node这个头动 那么定义一个tmp代替node
                    tmp.next=cur;
                    tmp=tmp.next;
                    cur=cur.next;
                }
            }
            //把最后一个节点的next置为空 防止死循环
            tmp.next=null;
            //每一次都返回头的next node一直随着tmp的移动而变化的
            return node.next;
        }
    }
}

回文结构即是数据从前往后读 和 从后往前读 都是相同的

 public boolean chkmid(){
            if(this.head==null){
                return false;
            }
            if(this.head.next==null){
                return true;
            }
            //1.找到单链表的中间结点
            Node fast=this.head;
            Node slow=this.head;
            while(fast!=null||fast.next!=null){
                fast=fast.next.next;
                slow=slow.next;
            }
            //2.反转单链表的后半部分 slow肯定在中间位置
            Node cur=slow.next;
            while(cur!=null){
                Node curNext=cur.next;
                cur.next=slow;
                slow=cur;
                cur=curNext;
            }
            //slow此时为最后一个节点了
            //3.一个从前往后走 一个从后往前走 看过程中是否有不相同的
            
            //当这两个指针不相遇时
            while(this.head!=slow){
                if(this.head.data!=slow.data){
                    return false;
                }
                //当链表中的个数为偶数时 这种情况存在
                if(this.head.next==slow){
                    return true;
                }
                this.head=head.next;
                slow=slow.next;
            }
            return true;
        }

 public boolean sss(){
            Node fast=this.head;
            Node slow=this.head;
            while(fast!=null&&fast.next!=null){
                 fast=fast.next.next;
                 slow=slow.next;
                 //说明他俩相遇
                 if(slow==fast){
                     return true;
                 }
                 //当存在null时说明无环
                if (fast == null || fast.next == null) {
                    return false;
                }
            }
            return false;
        }

 

 

 public Node sss() {
            Node fast = this.head;
            Node slow = this.head;
            while (fast != null || fast.next != null) {
                fast = fast.next.next;
                slow = slow.next;
                //说明他俩相遇
                if (slow == fast) {
                    break;
                }
            }
            //当存在null时说明无环 即没有存在第一个入口点
            //它是因为fast 或fast.next为null时才退出
            if (fast == null || fast.next == null) {
                return null;
            }
            //不满足上面条件退出 证明是存在环的
            //那么此时我们 把slow指向头 slow与fast一步一步走
            //fast slow一步一走的相遇点即是第一次的入口点
            slow = this.head;
            while(fast!=slow){
                fast=fast.next;
                slow=slow.next;
            }
            return fast;//或return slow;都一样
        }

public Node lionelmessi(Node headA,Node headB) {
            //先假设出pl指向长的单链表 ps指向短的
            //如果到后面求差值时发现不正确 那么进行调换 反正规定pl指向长的 ps指向短的
            Node pl = headA;
            Node ps = headB;
            int lenA=0;
            int lenB=0;
            while (pl != null) {
        pl=pl.next;
        lenA++;
            }
            while(ps!=null){
                ps=ps.next;
                lenB++;
            }
            //求出两链表差值
            int len=lenA-lenB;
            pl=headA;
            ps=headB;
            //证明最长的是ps 而不是pl
            if(len<0){
                pl=headB;
                ps=headA;
            }
            //先让较长的一条 我们规定是pl指向最长的 
            // pl先走差值步 保证他俩在一条起跑线
            //再到之后pl ps各走一步 进行判断是否有公共点
            for(int i=0;i<len;i++){
                pl=pl.next;
            }
            while(pl!=null&&ps!=null&&ps!=pl){
                pl=pl.next;
                ps=ps.next;
            }
            if(pl==ps&&pl!=null&&ps!=null){
                return ps;
            }
            return null;
        }
    }

 

 public Node neymar(Node headA,Node headB){
            //1.首先申请一个虚拟节点 用作为合并后的头 把两个链表接到后面
            Node newhead=new Node(1);
            //2.设定headA headB分别指向两个链表


            //3.比较两个链表的数据 把较小的那一个接到newhead的后面

            //由于newhead不可发生改变所以 创建一个变量为tmp用来指向这个新头
            Node tmp=newhead;
            if(headA.data<headB.data){
                tmp.next=headA;
                tmp=tmp.next;
                headA=headA.next;
            } else {
                tmp.next=headB;
                tmp=tmp.next;
                headB=headB.next;
            }
            //4.当一个链条为空时 把另一个直接接到tmp后面
            //由于两个链表是相同长度的 所以只要接一次
            if(headA!=null){
                tmp.next=headA;
            } 
            if(headB!=null){
                tmp.next=headB;
            }
            return newhead;
        }
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值