刷题总结 | 链表总结篇

45 阅读1分钟

链表总结篇

总结刷过的链表题

2. 两数相加

一道模拟计算题,这里用了很多临时变量用于判断是否进位,是否为空。个人感觉很考验细节的一道题,逻辑大家都懂,细节很重要。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
       ListNode res = new ListNode(0);
       ListNode cur = new ListNode(0);
       cur.next = res;
       while(l1 != null || l2 != null){
           int v1 = l1 == null ? 0 : l1.val;
           int v2 = l2 == null ? 0 : l2.val;
           int v = cur.next.val + v1 + v2;
           cur.next.val = v % 10;
           l1 = l1 == null ? null : l1.next;
           l2 = l2 == null ? null : l2.next;
           if((v) / 10 >= 1){
               cur.next.next = new ListNode(1);
               cur.next = cur.next.next;
           }else if(l1 != null || l2 != null){
               cur.next.next = new ListNode(0);
               cur.next = cur.next.next;
           }
       }
       return res;
    }
}

19. 删除链表的倒数第 N 个结点

这道题是双指针法的小trick,找到倒数第n个节点。记住了就好!

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode slow = dummyHead;
        ListNode fast = dummyHead;
        for(int i = 0; i < n; i++){
            fast = fast.next;
        }
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummyHead.next;
    }
}

24. 两两交换链表中的节点

有点复杂的链表题,一开始想得是用三个指针,但其实是要定义三个临时变量、一个虚头节点和一个cur节点遍历就好操作了。链表的题做多了就感觉有思路了,还是多加练习吧。

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode cur = dummyHead;
        ListNode first;
        ListNode second;
        ListNode temp;
        while(cur.next != null && cur.next.next != null){
            first = cur.next;
            second = cur.next.next;
            temp = cur.next.next.next;
            cur.next = second;
            second.next = first;
            first.next = temp;
            cur = first;
        }
        return dummyHead.next;
    }
}

142. 环形链表 II

这道题依然是双指针的应用,比较考察数学功底。这里有两个数学结论可以直接使用

  1. 如果链表有换,fast一次走两步,slow一次走一步,双指针一定相遇。
  2. 指针相遇后,从相遇节点到环入口节点的距离 等于 头结点到环入口的距离
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(slow == fast){
                ListNode index1 = fast;
                ListNode index2 = head;
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

203. 移除链表元素

比较基础的链表操作,对链表进行增删改的时候使用虚头节点会更方便操作。而遍历链表一般是不需要虚头节点的

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode pre = new ListNode(){};
        pre.next = head;
        ListNode cur = pre;
        while(cur.next != null){
            if(cur.next.val == val){
                cur.next = cur.next.next;
            }else{
                cur = cur.next;
            }
        }
        return pre.next;
    }
}

206. 反转链表

也是比较经典的题,需要两个指针pre和cur,再定义一个temp临时变量储存下一个节点,想清楚逻辑的话,算是比较简单的一道题。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

707. 设计链表

也是二刷这道题了,花了半小时勉强做出来,主要还是考察对虚节点的使用,一般定义一个pre节点操作就可以了,我这里定义了pre和cur两个节点,其实有点多余。

class MyLinkedList {
    private int size;
    private ListNode head;

    public MyLinkedList() {
        this.size = 0;
        this.head = new ListNode(0);
    }
    
    public int get(int index) {
        if(index >= size || index < 0) return -1;
        ListNode cur = head;
        for(int i = 0; i <= index; i++){
            cur = cur.next;
        }
        return cur.val;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }
    
    public void addAtIndex(int index, int val) {
        if(index > size) return;
        if(index < 0) index = 0;
        ListNode pre = head;
        ListNode newNode = new ListNode(val);
        for(int i = 0; i < index; i++){
            pre = pre.next;
        }
        newNode.next = pre.next;
        pre.next = newNode;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if(index >= size || index < 0) return;
        ListNode cur = head;
        ListNode pre = new ListNode(0);
        pre.next = head;
        for(int i = 0; i <= index; i++){
            cur = cur.next;
            pre = pre.next;
        }
        pre.next = cur.next;
        size--;
    }
}

class ListNode {
    int val;
    ListNode next;
    ListNode(){}
    ListNode(int val){
        this.val = val;
    }
}

面试题 02.07. 链表相交

也算是一个小trick,通过让curA指针先移动两个链表的长度差,使得curA和curB两个指针对齐,来比较两个链表的尾部是否相同。感觉也没什么好的思路,先记下来吧

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = 0;
        int lenB = 0;
        ListNode a = headA;
        ListNode b = headB;
        while(a != null){
            a = a.next;
            lenA++;
        }
        while(b != null){
            b = b.next;
            lenB++;
        }
        a = headA;
        b = headB;
        if (lenB > lenA) {
            int tmpLen = lenA;
            lenA = lenB;
            lenB = tmpLen;
            ListNode tmpNode = a;
            a = b;
            b = tmpNode;
        }
        int gap = lenA - lenB;
        while(gap-- > 0){
            a = a.next;
        }
        while(a != null){
            if(a == b){
                return a;
            }
            System.out.println("curA =  " + a.val);
            System.out.println("curB =  " + b.val);
            a = a.next;
            b = b.next;
        }
        return null;
    }
}