leetcode 203 移除链表元素 707 设计链表 206 反转链表

74 阅读3分钟

- leetcode 203 移除链表元素 easy

题目链接: leetcode.com/problems/re…

思路: 利用dummynode方便实现全部节点共同操作,用pre节点和cur节点根据不同条件的改变而调节链表的链接关系。

代码:

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

提交报错 (2):

第1次: 错误总结,pre节点的改变需要分为不同情况,而不是像cur一样每次都改变。

第2次: 返回链表, dummynode是为了方便操作所创建的虚拟头结点,返回结果列表应从next起始。

- leetcode 707 设计链表 medium

题目链接: leetcode.com/problems/de…

思路: 链表题优先使用dummynode,但要想清楚在实际操作中dummynode会引起哪些变化,尤其在边界值问题。实现数据结构的题目代码量一定很大,耐住性子一点点根据需求补足所需代码也是关键点。链表结构的特殊属性就是size和虚拟头结点。

代码:

class LinkNode {
    int val;
    LinkNode next;
    public LinkNode () {}
    public LinkNode (int val) {
        this.val = val;
    }
    public LinkNode (int val, LinkNode next) {
        this.val = val;
        this.next = next;
    }
}

class MyLinkedList {
    ListNode node;
    private int size = 0;
    
    public MyLinkedList () {
        this.size = 0;
        node = new ListNode(-1, null);
    }

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

提交报错 (8):

第1次: LinkNode类缺失单val参数的构造函数,在代码量大,特殊情况多时,难以预料具体需要使用哪种constructor,可以把没种都实现一遍。

第2次: MyLinkedList构造函数无参生成虚拟头结点的构造方法没考虑清楚。

第3次: get方法写错。将index > this.size改成index >= this.size解决。 原因是边界值问题,在查询时,index == size的情况已经越界.

第4次: addAtTail是通过addAtIndex来实现的,在给addAtIndex传参时出现了错误。 将addAtIndex(this.size - 1, val);改成addAtIndex(this.size, val);解决。 原因是边界值问题,插入时index = size的情况正是尾插。

第5次: addAtIndex是整个代码的重点部分,理论上包含了3个函数的实现。而代码逻辑最为混乱,整个代码段参考卡哥重构。

第6次: deleteAtIndex和addAtIndex在while循环时没想清楚再增删时,要找到的节点正是index - 1

第7次: get方法错将while(index >= 0)写成while(index > 0)导致输出错误。原因是没想清楚边界值,要找的位置是index本身,而不是index-1的位置。

第8次: deleteAtIndex方法想不清边界情况,加了dummy以后,cur=cur.next与给定链表index刚好一致。 index == 0的情况是例外,只有一个节点,需要特殊处理删除。

- leetcode 206 反转链表 easy

题目链接: leetcode.com/problems/re…

思路: 事先理清楚改变节点方向的过程是2个节点改变指向,然后改变节点位置。cur节点最终会出链表,因此返回pre才是改变后的头结点。

迭代代码:

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

提交报错 (2):

第1次: 在改变前两个节点的指向后,画蛇添足改变了tmp第三节点的指向再移动节点,实际上只需要与tmp、cur交换变化节点即可。

第2次: 总结,dummynode需改用null,因为它最终会作为反转后链表的最后一个节点的指向。

递归代码:

class Solution {
    public ListNode reverseList(ListNode head) {
        return reverseNode(null, head);
    }
    public ListNode reverseNode(ListNode prev, ListNode cur) {
        if (cur == null) {
            return prev;
        } else {
            ListNode tmp = cur.next;
            cur.next = prev;
            return reverseNode(cur, tmp);
        }
    }
}

提交报错 (1):

第1次: 递归需要重新写一个函数能够交换两个节点形参,从头部位置开始传参,直到最终cur为null证明链表结束。递归在实现改变2个节点指向的同时,也需要递归交替移动2个节点位置。