Решал эту проблему, на самом деле доделал. Однако я все еще хочу улучшить свое решение. Например, есть ли другой подход к решению этой проблемы, позволяющий уменьшить временную сложность? мое решение '...

-1
omar ahmed 7 Июл 2021 в 18:32

4 ответа

Лучший ответ

Ваше итеративное решение выглядит нормально, хотя я бы посоветовал упростить ваш фактический код подсчета примерно до следующего:

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]);
0
RaffleBuffle 7 Июл 2021 в 16:46

Это легко сделать в сложных условиях 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;
}
-1
GURU Shreyansh 7 Июл 2021 в 16:28

Ваш код оптимистично настроен по поводу количества узлов в списке. Он вернет 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).

0
trincot 7 Июл 2021 в 18:34

Предполагая, что вы хотите сохранить постоянную сложность пространства O (1), ваше решение выглядит оптимальным. Я также предполагаю, что это односвязный список.

Кстати, временная сложность вашего решения не O (n ^ 2). Оно включено). Вы делаете один обход, чтобы получить общее количество. Это O (n). Вы делаете еще один обход, чтобы получить количество узлов k. Это два независимых обхода. Таким образом, временная сложность равна n + n = 2n или O (n). Внутреннего цикла нет, поэтому ваше решение работает с временной сложностью O (n).

0
aatwork 7 Июл 2021 в 16:02