代码随想录Day3 | 203.移除链表元素、707.设计链表、206.反转链表 | 链表操作

631 阅读2分钟

203. 移除链表元素

题目链接:203. 移除链表元素 - 力扣(LeetCode)

思路: 两个指针一个pre指向虚拟头节点,一个cur指向head,cur不为null时,进行循环,当cur的值等于target时,pre指向cur的next节点,cur向后移。如果cur不等于目标值,pre和cur同时向后移。

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

        return dummy.next;
    }
}

总结:

707. 设计链表

题目链接:707. 设计链表 - 力扣(LeetCode)

思路: 每个方法的思路都是正确的,但是具体实现的时候总是有各种问题orz。刚开始没有想到构造函数里要放size来存储链表的长度。addAtHead方法刚开始写的是 cur.next = head.next, 缺了 head.next = cur这一步。

//正解 
class MyLinkedList {

    int size;
    ListNode head;
    
    public MyLinkedList() {
        size = 0;
        head = new ListNode(0);
    }
    
    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode cur = head.next;
        while (index > 0) {
            cur = cur.next;
            index--;
        }
        return cur.val;
    }
    
    public void addAtHead(int val) {
        ListNode cur = new ListNode(val);
        cur.next = head.next;
        head.next = cur;
        size++;
    }
    
    public void addAtTail(int val) {
        ListNode cur = new ListNode(val);
        ListNode pre = head;
        while (pre.next != null) {
            pre = pre.next;
        }
        pre.next = cur;
        size++;

        // addAtIndex(size, val);
    }
    
    public void addAtIndex(int index, int val) {
        if (index < 0 || index > size) {
            return;
        }
        ListNode cur = new ListNode(val);
        ListNode pre = head;
        while (index > 0) {
            pre = pre.next;
            index--;
        }
        cur.next = pre.next;
        pre.next = cur;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        ListNode pre = head;
        while (index > 0) {
            pre = pre.next;
            index--;
        }
        pre.next = pre.next.next;
        size--;
    }
}

总结:

构造函数中初始化size来记录链表的长度,并且在每次删除、添加、插入之后更新size的值。使用dummyhead作为虚拟头节点来方便处理,链表删除和插入操作中,指针应该指向待插入/删除的节点前一位,同时在操作的时候要注意顺序。

206. 反转链表

题目链接:206. 反转链表 - 力扣(LeetCode)

思路:

  1. 常规解法,一前一后两个指针,用temp保存cur.next的值。
  2. 递归做法没有思路

我的代码:

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode dummy = new ListNode();
        dummy.next = head;
        ListNode pre = dummy;
        ListNode cur = head;
        pre.next = null;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
}
Output: [5,4,3,2,1,0]
Expected Output: [5,4,3,2,1]

正确解法:

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

递归解法:

和双指针一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        return reverse(cur, pre);
    }

    public ListNode reverse(ListNode cur, ListNode pre) {
        // 终止条件
        if (cur == null) return pre;
        ListNode temp = cur.next;
        cur.next = pre;
        return reverse(temp, cur);
    }
}

问题:

  1. 头节点的初始化搞错了,知道pre的值应该设置为null,但是忘了可以直接写ListNode pre = null;
  2. return的返回值搞错了,第一遍写成return dummy.next,发现错误之后又改成return cur.next。

总结:

复习了反转链表的过程。