面试题18:删除链表的结点

题目:

在O(1)时间内删除链表结点。

给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间内删除该节点。

分析:

在单向链表中删除结点,常规的做法是从链表的头结点开始,顺序遍历查找要删除结点的前一个结点,因为要让prev的next指向要删除结点的next结点,再删除掉这个要删除的结点。此时的时间复杂度是O(n)。怎么实现O(1)时间删除链表结点呢?

已知要删除结点,我们可以轻松获取到next结点,我们将next结点的值复制到要删除结点,将next结点删除掉,仿佛可以达到一样的效果,此时的时间复杂度是O(1)。

不过这个思路有一个问题,如果要删除的结点位于最后一个结点,它没有next结点,此时我们只能从头结点开始顺序遍历,来实现删除。如果链表中只有一个结点,这个结点既是头结点,又是尾结点,那么就要把链表置空了。

值得注意的是,上面的理论基于一个假设:要删除的结点在链表中。我们需要O(n)的时间才能判断链表中是否包含某一结点。受O(1)时间限制,我们不得不把确保结点在链表中的职责退给函数delete()的调用者。

解法:

package com.wsy;

class Node {
    private int value;
    private Node next;

    public Node() {
    }

    public Node(int value, Node next) {
        this.value = value;
        this.next = next;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

public class Main {
    public static void main(String[] args) {
        Node head = new Node(10, null);
        Node tail = head;
        Node deleteNode = null;
        for (int i = 0; i < 10; i++) {
            Node node = new Node(i, null);
            tail.setNext(node);
            tail = node;
            if (i == 5) {// 删除链表中某个结点
                deleteNode = node;
            }
        }
        deleteNode = tail;// 删除链表中的尾结点
        head = head.getNext();
        forwardPrint(head);
        delete(head, deleteNode);
        forwardPrint(head);
    }

    public static void forwardPrint(Node head) {
        Node node = head;
        while (node != null) {
            System.out.print(node.getValue() + "->");
            node = node.getNext();
        }
        System.out.println();
    }

    public static void delete(Node head, Node deleteNode) {
        if (head == null || deleteNode == null) {
            return;
        }
        if (deleteNode.getNext() != null) {// 删除链表中的一个结点
            Node next = deleteNode.getNext();
            deleteNode.setValue(next.getValue());
            deleteNode.setNext(next.getNext());
            next = null;
        } else if (head == deleteNode) {// 链表只有一个头结点的删除
            head = deleteNode = null;
        } else {// 链表有多个结点,删除尾结点
            Node node = head;
            while (node.getNext() != deleteNode) {
                node = node.getNext();
            }
            node.setNext(null);
            deleteNode = null;
        }
    }
}

题目:

删除链表中重复怒的结点。

在一个排序的链表中,如何删除重复的结点?

比如,链表1→2→3→3→4→4→5,删除重复结点后为:1→2→5。

分析:

解决这个问题第一步是确定删除函数的参数。当然,这个函数需要输入待删除链表的头结点。头结点可能与后面的结点重复,也就是说头结点也可能被删除。

从头结点开始遍历链表,如果当前结点的值和下一个结点的值相同,那么它们就是重复的结点,都需要被删除,为了保证删除后链表仍然是连续的,我们要把当前结点的前一个结点和后面值比当前结点的值大的结点相连,确保前一个结点始终与下一个没有重复的结点连接在一起。

解法:

package com.wsy;

class Node {
    private int value;
    private Node next;

    public Node() {
    }

    public Node(int value, Node next) {
        this.value = value;
        this.next = next;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

public class Main {
    public static void main(String[] args) {
        Node head = init();
        forwardPrint(head);
        head = deleteDuplication(head);
        forwardPrint(head);
    }

    public static Node init() {
        Node node7 = new Node(5, null);
        Node node6 = new Node(4, node7);
        Node node5 = new Node(4, node6);
        Node node4 = new Node(3, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        return node1;
    }

    public static void forwardPrint(Node head) {
        Node node = head;
        while (node != null) {
            System.out.print(node.getValue() + "->");
            node = node.getNext();
        }
        System.out.println();
    }

    public static Node deleteDuplication(Node head) {
        if (head == null) {
            return null;
        }
        Node prev = null;
        Node node = head;
        while (node != null) {
            Node next = node.getNext();
            if (next != null && next.getValue() == node.getValue()) {
                int value = node.getValue();
                while (node != null && node.getValue() == value) {// 多个重复的结点在一起
                    Node deleteNode = node;
                    node = node.getNext();
                    deleteNode = null;
                }
            } else {
                prev = node;
                node = next;
            }
            if (prev == null) {// 头结点是重复的结点
                head = node;
            } else {
                prev.setNext(node);
            }
        }
        return head;
    }
}
发布了172 篇原创文章 · 获赞 1 · 访问量 7168

猜你喜欢

转载自blog.csdn.net/qq_36059561/article/details/104141413