移除链表元素+反转链表+中间结点+倒数第k个结点+合并有序链表OJ题(图解+解题步骤+思路+代码)


链表常见面试题


一、 移除链表元素

1. 题目

在这里插入图片描述

2.思路

  • 1.设置两个并行的结点,一个是cur结点,一个是cur的前驱结点
  • 2.由cur遍历结点,判断等于cur,前驱结点存cur后一个结点的地址值,cur后移
  • 3.cur不等于,前驱结点移动带cur,cur后移,也就是说,等于要删除的元素,跳过,不等于的保留

3.图解

在这里插入图片描述

4.解题步骤

  • 1.判断头结点是否为空
  • 2.设置prev为头结点,cur为下一个结点(头结点等于val的情况最后考虑)
  • 3.遍历链表,直到cur==null为止
  • 4.如果cur的值等于val,prev的next域引用cur下一个结点的地址,cur后移一位
  • 5.否则,prev移动到cur,cur后移一位
  • 6.最后处理头结点,如果头结点刚好等于val,将头结点后移一位。

5.代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {//如果头结点为空,直接返回
            return null;
        }
        ListNode prev = head;
        ListNode cur = head.next;
        while (cur != null) {
            if (cur.val == val) {
                prev.next = cur.next;
                //cur = cur.next;
            } else {
                prev = cur;
                //cur = cur.next;
            }
            cur = cur.next;
        }
        if (head.val == val) {//最后处理头结点
            //如果头结点的值等于key,头结点后移
            head = head.next;
        }
        return head;
        
    }
}

作者:翁佳明 
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二、反转链表

1.题目

在这里插入图片描述

2 图解

在这里插入图片描述

3.思路

将头结点断开,然后后面的结点用头插法,依次插到前面,完成链表的反转

4.解题步骤

  • 1.先分别判断头结点是否为空,是否只存在一个结点
  • 2.设置头节点的下一个结点为cur结点
  • 3.断开头节点
  • 4.遍历链表,直到cur为空,设置curNext结点,存储cur下一个结点的位置
  • 5.让头节点连上cur,头节点移动到cur位置
  • 6.将cur移动到记录的curNext结点

5.代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
       if (head == null){//判断头结点是否为空
            return null;
        }
        if (head.next == null){
            return  head;//再判断是否只有一个结点,返回这个结点
        }
        ListNode cur = head.next; //cur为头结点的下一个结点
        head.next = null;//先让头结点断开,不指向任何结点
        while (cur!=null){
            ListNode curNext = cur.next;//curNext结点是cur的下一个结点
            cur.next = head;//将当前的cur后面连上head结点
            head = cur;//头结点移动到cur的位置
            cur = curNext;//将cur移动到记录的curNext结点
        }
        return head;
    }
}

三、链表的中间结点

1.题目

在这里插入图片描述

2.思路

  • 利用快慢指针找到中间结点
  • slow走一步,fast走两步
  • fast和slow同时出发,fast速度是slow的速度的一倍,路程相等,当fas到达终点,slow到达中间
  • fast等于空和fast.next等于空时停下,返回slow位置的结点

3.图解

在这里插入图片描述

4.解题步骤

  • 1.将fast和slow设立在头结点的位置
  • 2.fast刚好走到末尾时,fast.next为空,链表的结点是奇数个,fast如果走出链表,此时fast为空,链表的结点是偶数个,无论哪种情况,slow都是符合要求的中间结点
  • 3.fast== null || fast.next==null是循环截止的条件
  • 4.fast != null && fast.next !=null是循环运行的条件
  • 5.让slow一次走一步,fast一次走两步
  • 6.返回slow位置的结点,就是中间结点

5.代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

四、链表中倒数第K个结点

1.题目

在这里插入图片描述

2.思路

  • 利用快慢指针
  • 倒数第k个结点,相当于从倒数第1的结点开始,向前走k-1步
  • 只要设置fast和slow两个指针,相差k-1步,同时移动
  • 当fast走到末尾 ,slow就是倒数第k个结点

3.图解

在这里插入图片描述

4.解题过程

  • 判断k的合法性 同时避免空指针异常
  • 在头结点是位置设立fast和slow两个指针
  • 先让fast走k-1步,同时判断k是否超出链表长度
  • 让fast和slow同时移动,直到fast的next为空
  • 返回slow位置的结点

5.代码

 
/*public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(k <= 0 || head==null){//避免空指针异常
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while(k-1!=0){//fast先走k-1步
            fast = fast.next;
            if(fast==null){
                return null;//fast为空,说明k的值超出链表长度
            }
            k--;
        }
        while(fast.next!=null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

五、合并两个有序链表

1.题目

在这里插入图片描述

2.思路

  • 1.比较两个链表的头结点的值,用一个新的结点指向小的结点
  • 2.头结点和记录的tmp结点不断后移,依次连接
  • 3.最后返回新结点的下一个结点

3.图解

在这里插入图片描述

4.解题过程

  • 1.创建一个新的头结点,再用tmp代替新结点的移动
  • 2.循环比较两个链表当前头结点的值,小的有tmp指向
  • 3.移动tmp结点的位置,和两个链表头结点的位置
  • 4.当两链表其中之一走完时,循环结束
  • 5.tmp继续指向还没有走完的链表剩余的结点
  • 6.返回新结点的下一个结点,即合并新链表的头结点

5.代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode head1, ListNode head2 ) {
        ListNode newHead = new ListNode(0);//新创建一个结点
        ListNode tmp = newHead;//tmp结点代替newHead移动
        while (head1 != null && head2 != null) {
            if (head1.val <= head2.val) {//判断;两个链表头结点的值
                tmp.next = head1;//tmp指向head1
                head1 = head1.next;//head后移
            } else {
                tmp.next = head2;
                head2 = head2.next;
            }
            tmp = tmp.next;//tmp后移
        }
        if (head1 != null) {//如果两个链表还没走完,让tmp指向剩余结点
            tmp.next = head1;
        }
        if (head2 != null) {
            tmp.next = head2;
        }
        return newHead.next;//返回头结点的下一个结点
    }
}

小剧场

在这里插入图片描述

点击移步博客主页,欢迎光临~

偷cyk的图

  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值