从链接列表末尾删除Kth节点的内存有效方法

时间:2017-10-30 10:27:50

标签: java algorithm linked-list space-complexity memory-efficient

这是几个已知解决方案的已知问题,但我目前的努力是尝试找到解决它的最有效方法,考虑内存使用(而不是时间复杂度)。

问题:鉴于单链接列表未知(但可能非常大)N,请删除Kth成员从列表的末尾。 0 <= K < N

如果K0,请删除列表的最后一个节点。如果K = N-1,请删除列表中的第一个节点。

我最初的方法是递归 - 它是最简单的写法,它的时间复杂度是O(N) - 遍历列表两次,到最后和后面。

public int removeKLast(Node<T> node, int k) {
    if (node.getNext() == null) {
        return k;
    } else {
        int current = removeKLast(node.getNext(), k);
        if (current == 0) {
            node.setNext(node.getNext().getNext());
        }
        return current - 1;
    }
}

它有一些需要解决的最终案例(比如从列表中删除第一个节点)但其他方面很简单。

我的问题是这个实现意味着整个链表存储在内存中,其中包含与对象相关的开销。我想知道是否可以找到更有效的解决方案(仍然在O(N)时间内,最多在列表上运行两次),在任何给定时间内在内存中使用最多K个原始内容。

2 个答案:

答案 0 :(得分:2)

开始列表遍历。 K步后启动第二个迭代器,然后并行行走。当第一个迭代器到达结尾时,第二个迭代器站在要删除的节点上。

这种方法不能改变O(n)复杂度并执行大约2n(2n-k)步操作,但不包括最终发现和删除之间的“延迟”

答案 1 :(得分:1)

首先考虑检索列表大小:

public int size(Node<T> node) {
   int size = 0;
   if(node != null) {
   for(; node.getNext() != null; node = node.getNext())
       size++;
   }
   return size;
}

然后你可以一次性删除k - 前一次:

public int removeKLast(Node<T> node, int size, int k) {
    for(int i = 0; node = node.getNext() && i < size - k - 1; ++i) {}
    node.setNext(node.getNext().getNext());
}

需要额外内存:1个int类型的变量(大小)。 时间复杂度:O(n)。

您错过了解释如何存储头节点,因此当您尝试删除第一个节点时,此实现将不起作用。修复此问题所需的修改类似于:

public void removeKLast(Node<T> node, int size, int k) {
    if(k == size - 1) {
        node.setHead(node.getHead().getNext());
    } else {
        for(int i = 0; node = node.getNext() && i < size - k - 1; ++i) {}
        node.setNext(node.getNext().getNext());
    }
}