有关以下内容的问题:查找链表最后n个节点的总和

sauutmhj  于 2021-08-25  发布在  Java
关注(0)|答案(4)|浏览(302)

我正在解决这个问题,实际上我已经完成了。但是,我仍然希望改进我的解决方案。是否有其他方法可以解决此问题,从而降低时间复杂度?我的解的时间complextiy是o(n^2)。此外,我想了一种递归求解的方法,但最后我把两者混合了起来;正如我将“迭代地”遍历以获得 numOfNodes 然后“递归地”遍历以计数最后的节点。我还没有实现它,但我对这个解决方案感到困惑,我不知道它是否正确!

**请先看一看代码,,,,,,,,,,,,,,,,,,,,,,关于它的想法是计数 numOfNodes 在列表中,然后再次遍历,但对于每个节点,我将减少 numOfNodes . 什么时候 numOfNodes == k ,然后使用for循环计算总和。

代码如下:

public int sum(Node head, int k){
      int sum = 0;
      int numOfNodes = 0;

      Node temp = new Node(0);
      temp = head;

      while(temp != null){
          numOfNodes++;
          temp = temp.next;
      }

      temp = head;

      while(temp != null){
          if(numOfNodes == k){
            for(int i = 0; i<k; i++){
                sum += temp.data;
                temp = temp.next;
            }
          }else{
            numOfNodes--;
            temp = temp.next;
          }
      }

      return sum;
    }

提前谢谢你!

weylhg0b

weylhg0b1#

您的代码对列表中的节点数表示乐观。当列表少于时,它将返回0 k 节点。我认为在这种情况下,应该返回所有节点的总和。
至于算法的其余部分:它很好。它使用恒定的辅助内存,并以线性时间运行。它并不像您所想的那样是二次的:尽管您在列表中循环了第二次,但这只会使迭代次数o(2n),仍然是o(n)。
您还可以通过跟踪滞后的第二个节点引用,将两个迭代合并为一个迭代 k 前导节点引用后面的节点。
下面是它的外观:

public static int sum(Node head, int k){
    int total = 0;
    Node lag = head;
    Node lead = head;
    while (lead != null) {
        if (--k < 0) {
            total -= lag.data;
            lag = lag.next;
        }
        total += lead.data;
        lead = lead.next;
    }
    return total;
}

递归解决方案的缺点是需要o(k)堆栈空间。

9q78igpj

9q78igpj2#

假设您希望保持空间复杂度为常数o(1),那么您的解决方案看起来是最优的。我还假设它是一个单链表。
顺便说一下,解决方案的时间复杂度不是o(n^2)。它是o(n)。您正在进行一次遍历以获得总计数。这就是o(n)。您正在进行另一次遍历以获得k个节点的计数。这是两个独立的遍历。所以时间复杂度是n+n=2n或o(n)。没有内部循环,因此您的解决方案在o(n)时间复杂度下工作。

cqoc49vn

cqoc49vn3#

您的迭代解决方案看起来不错,但我建议您将实际计数代码简化为以下内容:

Node temp = head;
for(int i=0; i<numOfNodes-k; i++) 
    temp = temp.next;

// temp now points to the first node to be counted

int sum = 0;
for(int i=0; i<k; i++) 
{
    sum += temp.data;
    temp = temp.next;
}
return sum;

您提到的递归解决方案的优点是只需遍历列表一次,计算顶部 k 返回途中的节点。请注意,我们必须使用一个参考值(我使用的是一个简单的单元素数组),以保持计算出的限制,超过该限制,我们应该对节点进行计数。

static int sumr(Node node, int pos, int k, int[] lim)
{
    if(node == null)
    {
        // pos now holds the length of the list
        lim[0] = pos-k;
        return 0;
    }

    int sum = sumr(node.next, pos+1, k, lim);
    if(pos >= lim[0]) sum += node.data;
    return sum;
}

致电:

int sum = sumr(head, 0, 3, new int[1]);
a0zr77ik

a0zr77ik4#

它可以很容易地在计算机中完成 O(N) 时间和 O(1) 空间复杂性。
其思想是迭代列表一次,并计算列表中的节点数。让列表的大小为 size .
现在再次迭代列表并跟踪访问的节点。如果 i 在所需范围内(最后 k 节点),然后将这些节点的值添加到结果中 sum .

int i=1;
int sum = 0;
Node pointer = head;
while (pointer != null)
{
    if ((size-k) <= i)
    {
        sum += pointer.data;
    }
    i++;
    pointer = pointer.next;
}

相关问题