代码随想录算法训练营第三天|203.移除链表元素、707.设计链表、206.反转链表

648 阅读2分钟

203.移除链表元素

题目链接:203.移除链表元素

思路:创建一个虚拟头结点,用来保证删除第一个元素和删除其他元素的操作相同。

时间复杂度:O(n)

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode headnode = new ListNode(-1, head); // 创建虚拟头结点
        ListNode i = headnode;
        while (i != null && i.next != null) {
            while (i.next != null && i.next.val == val) { // 注意删除连续的节点
                i.next = i.next.next;
            }
            i = i.next;
        }
        return headnode.next;
    }
}

随想录的解法,思路上是一样的,但是代码逻辑更加清晰

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummy = new ListNode(-1, head); // 虚拟头结点
        ListNode pre = dummy; // 当前节点的上一个节点
        ListNode cur = head; // 当前节点
        while (cur != null) {
            if (cur.val == val) {
                pre.next = cur.next;
            } else {
                pre = cur;
            }
            cur = cur.next;
        }
        return dummy.next;
    }
}

707.设计链表

题目链接:707.设计链表

思路:题目要求可以设计所有类型的链表,这里选择设计带虚拟头结点的单链表。

时间复杂度:除了在第一个节点之前插入节点为O(1),其他都是O(n)

class MyLinkedList {

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

    private ListNode head; // 头结点
    private int len; // 链表长度


    public MyLinkedList() {
        head = new ListNode(0);
        len = 0;
    }
    
    public int get(int index) {
        ListNode i = head.next;
        while (i != null) {
            if (index == 0) {
                return i.val;
            }
            index--;
            i = i.next;
        }
        return -1;
    }
    
    public void addAtHead(int val) {
        ListNode newNode = new ListNode(val, head.next);
        head.next = newNode;
        len++;
    }
    
    public void addAtTail(int val) {
        ListNode i = head;
        while (i.next != null) {
            i = i.next;
        }
        ListNode newNode = new ListNode(val);
        i.next = newNode;
        len++;
    }
    
    public void addAtIndex(int index, int val) {
        if (index < 0) {
            addAtHead(val);
        }
        ListNode newNode = new ListNode(val);
        ListNode i = head;
        while (i != null) {
            if (index == 0) {
                newNode.next = i.next;
                i.next = newNode;
                len++;
                return;
            }
            index--;
            i = i.next;
        }
    }
    
    public void deleteAtIndex(int index) {
        if (index >= 0 && index <= len -1) {
            ListNode i = head;
            while (i != null && i.next != null) {
                if (index == 0) {
                    i.next = i.next.next;
                    len--;
                    return;
                }
                index--;
                i = i.next;
            }
        }
    }
}

这里不再粘贴随想录上的解法了,链表的基本操作思路比较固定,代码细节上和随想录有些许不同。

206.反转链表

题目链接:206.反转链表

思路:我的解法相当于创建一个新的链表,然后遍历给出的链表的每个节点,用头插法插入到新的链表中,就是一个反转的链表。

时间复杂度:O(n)

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode headNode = new ListNode();
        // 遍历一次节点,每次插入到头结点后面
        ListNode i = head;
        ListNode temp;
        while (i != null) {
            temp = i.next;
            i.next = headNode.next;
            headNode.next = i;
            i = temp;
        }
        return headNode.next;
    }
}

这里看一下随想录上的解法,思路有所不同。将每个节点的next指针的指向改变,然后返回最后一个节点作为头结点。具体的代码实现可以用双指针法和递归法。

双指针法:

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode cur = head;
        ListNode temp = null;
        while (cur != null) {
            temp = cur.next;// 保存下一个节点
            cur.next = prev;
            prev = cur;
            cur = temp;
        }
        return prev;
    }
}

递归法:

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

    private ListNode reverse(ListNode prev, ListNode cur) {
        if (cur == null) {
            return prev;
        }
        ListNode temp = null;
        temp = cur.next;// 先保存下一个节点
        cur.next = prev;// 反转
        // 继续反转下一个节点。
        return reverse(cur, temp);
    }
}