【链表之练习题】

简介: 【链表之练习题】

翻转链表


    //反转链表
    //实质上是把每一个节点头插法,原本第一个节点变成最后一个节点
    public ListNode reverseList(){
            //链表为空
        if (head == null){
            return null;
        }
        //链表只有一个节点
        if (head.next == null ){
            return head;
        }
        ListNode cur = this.head.next;//先定义cur的位置
        this.head.next =null;//再把head.next置为空
        while(cur != null){
            ListNode curNext =cur.next;//再定义curNext在cur后面
            cur.next =this.head;//让cur的下一个等于头节点,就能把cur头插到head前面
            head = cur;//head给到cur
            cur = curNext;//cur再到curNext位置
        }
        return head;//返回头,就能返回一整个链表
    }
}


找到链表的中间节点


方法1:链表长度除以2得到中间节点

    //求链表中间节点
    //1.先求整个链表的长度
    //2.再求长度/2 就找到这个节点了
    public ListNode MiddleNode(){
            ListNode cur = this.head;
           int len = size();
           //让cur走到中间节点
        for (int i = 0; i < len/2; i++) {
            cur = cur.next;
        }
        return cur;
    }


方法2:


优化代码:快慢指针的引用


  1. 当fast == null时,遍历结束


  1. 当fast.next == null时,遍历结束


所以循环结束有两个条件:fast == null 或者 fast.next == null

    public ListNode MiddleNode1(){
        ListNode fast = this.head;
        ListNode slow = this.head;
        while (fast != null && fast.next != null ){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }


返回倒数第k个节点


    public ListNode findKthToTail(int k){
    //判断k的合法性
        if (k <= 0 || head == null){
            return null;
        }
        ListNode fast =head;
        ListNode slow =head;
        //先让fast走k-1步
        while(k-1 != 0){
            fast = fast.next;
            //如果k很大,这个判断可以让代码更高效
            if (fast == null){
                return null;
            }
            k--;
        }
        //slow和fast同时走
        //当fast.next =null时,slow已经在倒数第k个节点了
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }


合并两个有序链表


public class Test {
    //定义两个链表
    public static MySingleList.ListNode  mergeTwoLists(MySingleList.ListNode head1, MySingleList.ListNode head2){
        //定义一个虚拟节点,保存合并之后的新链表
        MySingleList.ListNode newH = new MySingleList.ListNode(-1);
        //newH节点是新链表的头节点,跟着记录串联之后的节点
        MySingleList.ListNode tmpH = newH;
        //当两个链表都不为空才能进入循环进行合并排序
        while(head1 != null && head2 != null){
        //当head1的值小于head2时,头节点tmpH的下一个节点就是连接小的那一个,然后head1再往后走一步           
         if (head1.val < head2.val){
                tmpH.next = head1;
                head1 = head1.next;
            }else{
            //当head2的值小于head1时,头节点tmpH的下一个节点就是连接小的那一个,然后head2再往后走一步  
                tmpH.next = head2;
                head2 = head2.next;
            }
            //无论进入那个语句,tmp都会往后走一步
            tmpH = tmpH.next;
        }
        //当head1没走完了,说明head2走完了,继续接着剩下的head1
        if(head1 != null){
            tmpH.next = head1;
        }
        //当head2没走完了,说明head1走完了,继续接着剩下的head2
        if(head2 != null){
            tmpH.next = head2;
        }
        //最后返回
        return tmpH;
    }
    public static void main(String[] args) {
        MySingleList mySingleList = new MySingleList();
        mySingleList.addLast(12);
        mySingleList.addLast(23);
        mySingleList.addLast(34);
        mySingleList.addLast(45);
        mySingleList.display();//打印数组
        MySingleList mySingleList2 = new MySingleList();
        mySingleList2.addLast(15);
        mySingleList2.addLast(24);
        mySingleList2.addLast(37);
        mySingleList2.addLast(166);
        mySingleList2.display();
        MySingleList.ListNode head = mergeTwoLists(mySingleList.head,mySingleList2.head);
        mySingleList.display();
    }


判断链表是否回文


1.先找到中间节点


2.翻转


3.前面往后走,后面往前走,值是否一样

    //判断是否回文
    public boolean chkPalindrome(){
            ListNode fast = head;
            ListNode slow = head;
            int len = size()/2;//5/2=2
            //1.找中间位置
        while(fast != null && fast.next != null){
            //fast先走俩步,slow再走一步
            fast = fast.next.next;
            slow = slow.next;
        }
        //2.翻转
        ListNode cur = slow.next;
        while(cur != null){
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //3.从前到后,从后到前
        while(head != slow){
            if (head.val != slow.val){
                return false;
            }
            //考虑偶数链表
            if (head.next == slow){
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;
    }


注意


在写题过程中,我混淆了找中间节点和返回倒数第k个节点的方法


他们的区别其实是:


找中间节点 :fast永远是slow的二倍,slow走一步,fast就走两步。

返回倒数第k个节点 :fast和slow的关系不是固定的,fast走几步根据k-1得到,还有一个区别是,fast走了k-1步之后,slow走一步,fast也是走一步

相关文章
|
2天前
|
安全
链表练习题-2
链表练习题
|
2天前
|
存储
链表练习题-1
链表练习题
|
2天前
【无头双向链表和链表练习题2】
【无头双向链表和链表练习题2】
25 0
|
7月前
|
存储 算法
做几个链表相关的练习题吧!!
做几个链表相关的练习题吧!!
29 1
|
2天前
|
算法
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
|
2天前
|
存储
LeetCode刷题---817. 链表组件(哈希表)
LeetCode刷题---817. 链表组件(哈希表)
|
2天前
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解
|
2天前
|
算法 安全 数据处理
LeetCode刷题---707. 设计链表(双向链表-带头尾双结点)
LeetCode刷题---707. 设计链表(双向链表-带头尾双结点)
|
2天前
leetcode代码记录(移除链表元素
leetcode代码记录(移除链表元素
10 0
【每日一题】LeetCode——链表的中间结点
【每日一题】LeetCode——链表的中间结点