【问题标题】:Find the maximum sum of first and last element of a linked list查找链表的第一个和最后一个元素的最大和
【发布时间】:2023-03-09 10:53:01
【问题描述】:

给定一个单向链表,其中每个元素都包含一个数字和一个指向链表头部的指针。对第一个和最后一个数据求和并删除这些节点。然后将生成的链表的第一个和最后一个数据相加,并删除这两个节点。
继续这样做,直到列表变空。 我们必须在 O(1) 空间复杂度中找到从结果总和中获得的最大总和。
该列表是一个具有偶数节点的单链表。

我的想法:

  1. 一种方法是在每次迭代时将指针移至最后一个元素,删除节点,并保留一个 maxSum 变量。这可能不是一个有效的解决方案。

【问题讨论】:

  • 这是一个单链表还是双链表?
  • 如果节点数为奇数会怎样?
  • @user1984 单链表,节点数为偶数
  • 一种方法是遍历链表一次并将后半部分 1->2->3->4 反转为 1->2; 3<-4 (可以使用快速和慢速指针找到中间然后反转以下列表从中间)。无论如何我们都必须删除节点,所以修改列表应该没问题。一旦完成,初始化一个指向原始头部的指针,中间已经结束。现在可以对最大值进行所需的删除和求和。
  • 如果不要求效率,你的建议可以接受。

标签: algorithm linked-list


【解决方案1】:

如果我理解正确的话,这个链表中的一个节点有两个指针:一个指向下一个节点的指针,一个指向链表中第一个节点的指针。

有几种方法可以解决这个问题。这是一个:

  • 遍历列表并更改每个节点中的头指针以引用前一个节点:这将为您提供一个双向链表。保留指向最后一个节点的指针。
  • 现在您可以从列表的两端开始并朝向彼此进行串联遍历。
  • 实际上并不需要在遍历期间删除节点。您甚至可以将列表恢复到第二步中的原始状态。

甚至可以在每个节点没有这个额外的头指针的情况下做到这一点。在这种情况下,反转列表的后半部分。

这是第一个想法的实现,在 JavaScript 中:

class Node {
    constructor(data, head) {
        this.data = data;
        this.head = head || this; // default is node itself
        this.next = null;
    }
}

function createList(...values) {
    if (!values) return null;
    let head = new Node(values.shift()); // First value
    let tail = head;
    for (let value of values) { // Remaining values
        tail.next = new Node(value, head);
        tail = tail.next;
    }
    return tail.head;
}

function maxPairSum(head) {
    if (!head) return -Infinity;
    // Make doubly linked list, (ab)using node's head member
    let tail;
    for (tail = head; tail.next; tail = tail.next) {
        tail.next.head = tail; // Next gets reference to previous
    }
    // Tandem walk, towards center
    let maxSum = -Infinity;
    for (let curr = head; curr != tail && curr != tail.next; curr = curr.next) {
        maxSum = Math.max(maxSum, curr.data + tail.data);
        tail = tail.head; // Is actually a reference to previous
    }
    // Restore head references (optional)
    for (let curr = head; curr; curr = curr.next) {
        curr.head = head;
    }
    return maxSum;
}

// Example run
let head = createList(2, 5, 1, 5, 4, 6);
let maxSum = maxPairSum(head);
console.log(maxSum);  // 9

...如果您想真正删除该列表,只需清除 head 引用即可。在 JavaScript 中,垃圾收集器将释放无法访问的内存;在其他一些语言(如 C)中,您需要在清除对头节点的引用之前显式释放每个节点占用的内存。

【讨论】:

    【解决方案2】:
    private static int max = 0, count = 0;
    private static LinkedList top;
    static int maximumPagesRec(LinkedList tail) {
        if(tail.next==null)
            max = max<top.data + tail.data ?top.data + tail.data: max;
        else if(tail == top && count++ !=0){
            max = max<top.data ?tail.data: max;
        }
        else if(top.next == tail && count++!=1)
            max = max<top.data + tail.data ?top.data + tail.data: max;
    
        else {
            maximumPagesRec(tail.next);
        }
        top = top.next;
        return max;
    }
    static int maximumPages(LinkedList head)
    {   top = head;`enter code here`
        return maximumPagesRec(head);
    }
    

    【讨论】:

    • 您是如何对此进行测试的,结果如何?您对空间需求的评估是什么?
    【解决方案3】:

    如何将所有链表值元素推入堆栈,以1-&gt;2-&gt;3-&gt;4 为例,堆栈将为1234。 之后,我们逐一求和并删除每个链表,存储我们得到的最大值。

    【讨论】:

    • 这种方法的空间复杂度是 O(number_of_elements)。操作中提到需要 O(1) 空间复杂度。
    猜你喜欢
    • 1970-01-01
    • 2012-06-11
    • 2014-01-11
    • 2021-06-08
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多