手撕链表笔试题(超详细思路讲解)(第三期)

手撕链表笔试题(超详细思路讲解)(第三期)_第1张图片


文章目录

  • 前言
  • 一、Leetcode--234回文链表
    • 1.题目描述
    • 2.思路讲解
    • 3.代码实现
      • 3.1创建新链表
      • 3.2反转一半原链表
  • 二、Leetcode--21.合并两个有序链表
    • 1.题目描述
    • 2.思路讲解
    • 3.代码实现
      • 3.1迭代
      • 3.2递归写法
  • 三、Leetcode--面试题02.04.分割链表
    • 1.题目描述
    • 2.思路讲解
    • 3.代码实现


前言

本篇博客我们继续看链表笔试题第三期


一、Leetcode–234回文链表

1.题目描述

手撕链表笔试题(超详细思路讲解)(第三期)_第2张图片

2.思路讲解

1.此时我们可以开辟一个新的链表,新链表的节点恰好是原链表的反转,然后我们同步开始遍历这两个链表,若发现有一个值不相等,就不是回文链表
手撕链表笔试题(超详细思路讲解)(第三期)_第3张图片
手撕链表笔试题(超详细思路讲解)(第三期)_第4张图片
2.本题 还有一个进阶解法
在这里插入图片描述
题目要求使用O(n)的时间复杂度和O(1)的空间复杂度解决此问题,这就表示不能再创建新的链表,那我们就在原链表的基础上反转一半链表,再让两部分链表同时遍历
手撕链表笔试题(超详细思路讲解)(第三期)_第5张图片

3.代码实现

3.1创建新链表

//1.反转链表
public ListNode reverseList(ListNode head) {
        ListNode dummyHead = new ListNode();
        while (head != null){
            ListNode note = new ListNode(head.val);
            note.next = dummyHead.next;
            dummyHead.next = note;
            head = head.next;
        }
        return dummyHead.next;
    }
//判断是否是回文链表
    public boolean isPalindrome(ListNode head) {
        ListNode newLink = reverseList(head);
        while (head != null){
            if (head.val != newLink.val){
                return false;
            }
            head = head.next;
            newLink = newLink.next;
        }
        return true;
    }

3.2反转一半原链表

//判断是否是回文链表
 public boolean isPalindrome(ListNode head) {
        ListNode middleIndex = middleNode(head);
        ListNode newLink = reverseList(middleIndex);
        while (newLink != null){
            if (head.val != newLink.val){
                return false;
            }
            head = head.next;
            newLink = newLink.next;
        }
        return true;
    }
   //1.找中间结点
   public ListNode middleNode(ListNode head) {
       if (head == null || head.next == null){
           return head;
       }
       ListNode fast = head;
       ListNode low = head;
       while (fast != null && fast.next != null){
           fast = fast.next.next;
           low = low.next;
       }
       return low;
   }

   //反转链表
    public ListNode reverseList(ListNode head) {
       if (head == null || head.next == null){
           return head;
       }
       ListNode newHead = new ListNode();
       ListNode node = head.next;
       newHead = reverseList(head.next);
       node.next = head;
       head.next = null;
       return newHead;
    }

二、Leetcode–21.合并两个有序链表

1.题目描述

手撕链表笔试题(超详细思路讲解)(第三期)_第6张图片

2.思路讲解

1.通过读题,我们知道新链表是通过给定的两个链表的结点拼接组成的,表示没有创建新的结点,所以空间复杂度是O(1),题目要求拼接后的链表也是升序链表,所以我们可以创建一个虚拟头结点,然后遍历两个给定的链表l1和l2
手撕链表笔试题(超详细思路讲解)(第三期)_第7张图片
当l1和l2都不为空时,遍历两个链表,取最小值尾插如虚拟头结点之后,此时还得引入一个新的引用tail,表示当前新链表的尾结点
手撕链表笔试题(超详细思路讲解)(第三期)_第8张图片
(1).首先当l1和l2不为空的时候,遍历这两个链表
若l1.val <= l2.val,就把当前l1拼接到新链表的尾部,l1继续向后移动
反之,将l2拼接到新链表的尾部,l2继续向后移动
(2).当某个子链表为空,剩下的链表全部拼接到新链表的尾部
(3).返回dummyHead.next即可
2.本题还可以使用递归,我们看一下这个函数的语义
传入两个排序链表,就能把这两个链表合并为一个大的排序链表,返回拼接后头结点

3.代码实现

3.1迭代

 public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null){
            return list2;
        }
        if (list2 == null){
            return list1;
        }
        ListNode dummyHead = new ListNode();
        ListNode tail = dummyHead;
        while (list1 != null && list2 != null){
            if (list1.val <= list2.val){
                tail.next = list1;
                tail = list1;
                list1 = list1.next;
            }else{
                tail.next = list2;
                tail = list2;
                list2 = list2.next;
            }
        }if (list1 == null){
            tail.next = list2;
        }
        if (list2 == null){
            tail.next = list1;
        }
        return dummyHead.next;
    }

3.2递归写法

/**
     * 传入两个排序链表,就能把这两个链表合并为一个大的排序链表,返回拼接后头结点
     * @param list1
     * @param list2
     * @return
     */
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null){
            return list2;
        }
        if (list2 == null){
            return list1;
        }
        if (list1.val <= list2.val){
            list1.next = mergeTwoLists(list1.next,list2);
            return list1;
        }else{
            list2.next = mergeTwoLists(list1,list2.next);
            return list2;
        }
    }

三、Leetcode–面试题02.04.分割链表

1.题目描述

手撕链表笔试题(超详细思路讲解)(第三期)_第9张图片

2.思路讲解

本题的思路和上一题合并链表的思路相似
1.我们可以创建两个新的链表,新链表就是由原链表的结点组成的,一个链表smallHead存放小于x的结点,一个链表存bigHead放大于等于x的结点
手撕链表笔试题(超详细思路讲解)(第三期)_第10张图片
2.然后将bigHead.nex拼接到smallTail之后(smallTail.next = bigHead.next)
手撕链表笔试题(超详细思路讲解)(第三期)_第11张图片
3.返还smallHead.next即可

3.代码实现

public ListNode partition(ListNode head, int x) {
        if (head == null || head.next ==  null){
            return head;
        }
        ListNode smallHead = new ListNode();
        ListNode smallTail = smallHead;
        ListNode bigHead = new ListNode();
        ListNode bigTail = bigHead;
        while (head != null){
            if (head.val < x){
                smallTail.next = head;
                smallTail = head;
            }else{
                bigTail.next = head;
                bigTail = head;
            }
            head = head.next;
        }
        bigTail.next = null;
        smallTail.next = bigHead.next;
        return smallHead.next;
    }

你可能感兴趣的:(链表,算法,数据结构,java,开发语言)