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

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


文章目录

  • 前言
  • 一、Leetcode--206反转链表
    • 1.题目描述
    • 2.思路讲解
    • 3.代码实现
      • 3.1头插
      • 3.2迭代
      • 3.3递归写法
  • 二、Leetcode--876链表的中间节点
    • 1.题目描述
    • 2.思路讲解
    • 3.代码实现
      • 3.1遍历链表
      • 3.2快慢指针
  • 三、Leetcode--剑指offer22
    • 1.题目描述
    • 2.思路讲解
    • 3.代码实现
      • 1.遍历链表
      • 2.快慢指针


前言

本篇博客继续来看链表的笔试题


一、Leetcode–206反转链表

1.题目描述

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

2.思路讲解

本题一共有三种解法
1.边遍历原链表边新建一个新链表头插入新链表,头插的顺序刚好和原链表的顺序相反,这是在没有要求空间复杂度的情况下,若要求空间复杂度为O(1),那么此时就不能用这个解法
2.原地移动原链表,所谓的反转链表就是原来1指向2,现在2指向1
最后反转的链表1指向null
手撕链表笔试题(超详细思路讲解)(第二期)_第4张图片
那么就让prev从null开始走,然后cur = prev.next ,此时还需一个next引用暂存一下下一个节点的地址,然后不断的让三指针后移,并且不断的让cur指向prev,直到cur走到空,整个链表遍历结束,而prev恰好留在反转后的链表的头结点
手撕链表笔试题(超详细思路讲解)(第二期)_第5张图片
3.递归写法,我们把头结点之后的子链表交给子函数处理,然后把头结点拼接在反转后的链表后,然后要让head.next = null,因为此时head还指向的是第二个节点的地址,如果不断引用,就会形成一个环
手撕链表笔试题(超详细思路讲解)(第二期)_第6张图片

3.代码实现

3.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;
    }

3.2迭代

  /**
     * 迭代
     * @param head
     * @return
     */
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null){
        return head;
        }
        ListNode prev = null;
        ListNode cur = head;
        while (cur != null){
            ListNode note = cur.next;
            cur.next = prev;
            prev = cur;
            cur = note;

        }
        return prev;
    }

3.3递归写法

/**
     * 传入一个链表头结点,就能把这个链表反转,并且返回反转后的头结点
     * @param head
     * @return
     */
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        ListNode newHead = new ListNode();
        ListNode note = head.next;
        newHead = reverseList(head.next);
        note.next = head;
        head.next = null;
        return newHead;
    }

二、Leetcode–876链表的中间节点

1.题目描述

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

2.思路讲解

1.如果此时我们知道链表的长度,那么这个题就非常的简单,所以第一种思路就是遍历链表加计数,知道链表的长度后,我们让链表的长度为n,我们让middle这个引用从头开始走n / 2步就到了中间节点
奇数:1 -> 2 -> 3 -> 4 -> 5
此时长度为5 ==>5 / 2 = 2,从头开始走2步就到了中间节点
偶数:1 -> 2 -> 3 -> 4 -> 5 -> 6
此时长度为6–>6 / 2 = 3,从头开始走3步就到了中间结点
2.快慢指针,引入两个引用,让一个引用多走几步或者先走
那么对于这道题,我们引入两个指针,fast,low,让fast和low都从链表头开始走,fast一次走两步,low一次走一步,当fast走到null或者fast走到最后一个节点时,那么此时的low引用刚好指向链表的中间结点
手撕链表笔试题(超详细思路讲解)(第二期)_第8张图片
手撕链表笔试题(超详细思路讲解)(第二期)_第9张图片

3.代码实现

3.1遍历链表

 public ListNode middleNode(ListNode head) {
        int count = 0;
       for (ListNode x = head;x != null;x = x.next){
           count++;
       }
       ListNode middle = head;
       int middleIndex = count / 2;
        for (int i = 0; i < middleIndex; i++) {
            middle = middle.next;
        }
        return middle;
    }

3.2快慢指针

  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;
    }

三、Leetcode–剑指offer22

1.题目描述

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

2.思路讲解

1.如果拿到一个链表的长度,本题一样会变得很简单,拿到一个链表的长度n,我们只需要让一个引用从头结点开始走n - k步就走到了当前链表的倒数第k 个节点,但此时要注意k的合法性,此时k有可能大于size
1 -> 2 -> 3 -> 4 -> 5 , k = 2, n = 5 , n - k = 3
此时只需要从头结点向后走三步就到了倒数第二个节点
2.本题也可以用快慢指针的解法,同样引入fast和low两个引用,让fast和low都从头结点开始走,让fast先走k步,然后让双指针同时后移,当fast走到null时,low指针刚好指向倒数第k个节点

3.代码实现

1.遍历链表

public ListNode getKthFromEnd(ListNode head, int k) {
        if (head == null || k <= 0){
            return null;
        }
        int count = 0;
        for (ListNode x = head;x != null;x = x.next){
            count ++;
        }
        ListNode cur = head;
        for (int i = 0; i < count - k; i++) {
            cur = cur.next;
        }
        return cur;
    }

2.快慢指针

/**
     * 快慢指针的派生问题
     * @param head
     * @param k
     * @return
     */
    public ListNode getKthFromEnd(ListNode head, int k) {
        if (head == null || k <= 0){
            return null;
        }
        ListNode fir = head;
        ListNode sec = head;
        int count = 0;
        while (fir != null){
            fir = fir.next;
            count ++;
            if (count >= k + 1){
                sec = sec.next;
            }
        }
        if (k > count){
            return null;
        }
        return sec;
    }

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