手撕链表笔试题(超详细思路过程)(第一期)

在这里插入图片描述



前言

本篇博客我们一起来看看单链表的笔试题


一、Leetcode–203移除链表元素

1.1题目描述

在这里插入图片描述

1.2思路讲解

我们仔细看一下题目,题目需要删除所有值为val的节点,并返回新的头结点,也就是删除后链表的头结点,此时看到这道题跟链表的删除中的删除所有值为val的节点一样,重点讲一下,递归写法的思路,写递归的时候,我们一定要重视函数的语义
在这里插入图片描述
这个函数的要做的事就是:传入一个链表的头结点和待删除的值val,返回删除后的链表头结点,头结点之后的值为val的删除交给子函数
在这里插入图片描述

1.3代码实现

1.3.1迭代法

/**
 * 删除链表中所有值为val的结点
 */
public class Num203_RemoveLinkedListElement {
    
    
    public ListNode removeElements(ListNode head, int val) {
    
    
        while(head != null && head.val == val){
    
    
            ListNode x = head;
            head = head.next;
            x.next = null;
        }
        if (head == null){
    
    
            return null;
        }else{
    
    
            ListNode prev = head;
            while (prev.next != null){
    
    
                if (prev.next.val == val){
    
    
                    ListNode node  = prev.next;
                    prev.next = node.next;
                }else{
    
    
                    prev = prev.next;
                }
            }
        }
        return head;

    }

1.3.2虚拟头结点法

/**
     * 虚拟头结点法
     * @param head
     * @param val
     * @return
     */
    public ListNode removeElements(ListNode head, int val) {
    
    
        ListNode dummyHead = new ListNode();
        //记得连接当前链表
        dummyHead.next = head;
        ListNode prev = dummyHead;
        while(prev.next != null){
    
    
            if (prev.next.val == val){
    
    
                prev.next = prev.next.next;
            }else{
    
    
                prev = prev.next;
            }
        }
        return dummyHead.next;
    }

1.3.3递归写法

/**
     * 传入一个链表的头结点head和待删除结点值val,就能删除删除所有值为val的结点,并返回删除后的头结点
     * @param head
     * @param val
     * @return
     */
    public ListNode removeElements(ListNode head, int val) {
    
    
    if (head == null){
    
    
        return null;
    }
    //从第二结点开始的删除交给子函数
    head.next = removeElements(head.next,val);
    //只需要head的情况
        if (head.val == val){
    
    
            return head.next;
        }
        return head;
    }

二、Leetcode–83删除排序链表中的重复元素

1.题目描述

在这里插入图片描述

2.思路讲解

读题之后,我们发现本题和链表的普通删除是不一样的,普通的链表删除,是给定我们一个值或者给定一个索引,然后再删除,但是本题没有给,而我们不知道哪些节点是重复的,这就需要我们自己
1.先找找到链表中的重复节点
2.然后再根据题目要求进行操作
3prev —> 指向待删除节点的前驱,而此时一个引用是无法找到重复元素的,那我们就要引入第二个引用cur,cur = prev.next;
4.如果prev.val == cur.val,说明这两个节点重复
5.让prev = head; cur = prev.next;当出现重复元素时,prev一定是第一个重复的元素,此时让cur引用向后移动,知道碰到第一个和prev不相等节点,我们让prev.next = cur,此时我们就删除了重复节点,而且还保留了一个prev的值,与题目相吻合
在这里插入图片描述

3.代码实现

3.1迭代

public class Num83_DeleteDuplicates {
    
    
    public ListNode deleteDuplicates(ListNode head) {
    
    
        if (head == null || head.next == null){
    
    
            return head;
        }
        ListNode prev = head;
        ListNode cur = prev.next;
        while(cur != null){
    
    
            if (prev.val != cur.val){
    
    
                prev = prev.next;
            }else{
    
    
                prev.next = cur.next;
            }
            cur = cur.next;
        }
        return head;
    }
}

3.2递归写法

public class Num83_DeleteDuplicates {
    
    
   /**
     * 递归
     * 传入一个链表,就能删除其中值重复的结点,重复结点保留一次,并返回删除后的头结点
     *
     * @param head
     * @return
     */
    public ListNode deleteDuplicates(ListNode head) {
    
    
        if (head == null || head.next == null) {
    
    
            return head;
        }
        head.next = deleteDuplicates(head.next);
        if (head.val == head.next.val) {
    
    
            return head.next;
        }
        return head;
    }
}
}

三、 Leetcode–82删除链表的重复元素||

1.题目描述

在这里插入图片描述

2.思路讲解

读完题,我们发现这道题和83号题非常相似,但是区别是
83号题是删除重复节点,并保留一个重复的节点
本题是删除所有的重复节点,重复节点一个不留
1.如果使用82题的思路,那么第一个重复节点删不掉,单链表的删除都是通过前驱节点删除 — > 前驱节点删不掉,所以prev不能指向待删除的节点
2.此时prev不能指向重复节点,要判断重复节点就得再引入两个个引用,三引用
3.cur.val == nxet.val —> 判断重复元素
在这里插入图片描述
1.此时我们定义一个虚拟头结点,因为虚拟头结点一定不是待删除的元素,让prev从dummyHead开始走,让cur = prev.next; next = cur.next;
2.当发现cur.val != next,val,三指针同时后移
3.当cur.val == next.val ,就让next一直向后移动,直到碰到第一个不重复的节点
当next走到第一个不重复的节点,那么prev到next之间的所有结点都是待删除结点
4.prev — > 指向第一个重复结点的前驱
next — > 指向最后一个重复结点的后继
prev 到 next之间的所有节点都是待删除的节点

3.代码实现

3.1迭代

public class Num82_DeleteDuplicates {
    
    
    public ListNode deleteDuplicates(ListNode head) {
    
    
        ListNode dummyHead = new ListNode();
        dummyHead.next = head;
        ListNode prev = dummyHead;
        ListNode cur = prev.next;
      while (cur != null){
    
    
          ListNode next = cur.next;
          if (next == null){
    
    
              //当前链表只有一个结点
              //next走到空,所有节点删除完毕
              break;
          }else{
    
    
              //此时链表至少右两个以上的结点
              if (cur.val != next.val){
    
    
                  //三指针后移
                  prev = prev.next;
                  cur = cur.next;
              }else{
    
    
                  //此时碰到重复元素,让next一直后移,直到碰到第一个不重复的结点
                  while(next != null && cur.val == next.val){
    
    
                      next = next.next;
                  }
                  //说明碰到第一个不重复的结点
                  prev.next = next;
                  cur = next;
              }
          }
      }
      return dummyHead.next;
    }
}

3.2递归写法

public class Num82_DeleteDuplicates {
    
    
   /**
     * 传入一个排序链表,就能删除链表中所有的重复结点,返回删除后的链表的头结点
     *
     * @param head
     * @return
     */
    public ListNode deleteDuplicates(ListNode head) {
    
    
        if (head == null || head.next == null) {
    
    
            return head;
        }
        if (head.val != head.next.val) {
    
    
            head.next = deleteDuplicates(head.next);
            return head;
        } else {
    
    
            ListNode nextHead = head.next;
            while (nextHead != null && nextHead.val == head.val) {
    
    
                nextHead = nextHead.next;
            }
            return deleteDuplicates(nextHead);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_57011679/article/details/124678642