我正在尝试解决链接列表问题。给定单链表,修改前半节点的值,使得:
第一个节点的新值=最后一个节点的值 - 第一个节点的当前值
第二个节点的新值=第二个节点的值 - 第二个节点的当前值
示例:
给出链表1 - > 2 - > 3 - > 4 - > 5,
你应该返回4 - > 2 - > 3 - > 4 - > 5
到目前为止我能想到的解决方案是
这可能是最天真的解决方案。请问annyone请建议在时间/空间方面更有效的解决方案(想要避免多次迭代和堆栈的额外空间)?提前谢谢。
答案:
public ListNode subtract(ListNode a) {
ListNode slow =a;
ListNode fast=a;
ListNode head = a;
ListNode middle = null;
while(fast!=null && fast.next!=null)
{
if(fast.next.next!=null) // in case numOfNodes are even , we need to stay at middle
slow=slow.next;
fast = fast.next.next;
}
if(slow==fast)
return a;
middle = slow;
ListNode secondHalf = middle.next;
middle.next = null;
ListNode reversed = reverse(secondHalf);
ListNode temp1 = reversed;
while(temp1!=null ){
head.val = temp1.val - head.val;
temp1 = temp1.next;
head = head.next;
}
middle.next = reverse(reversed);
return a;
}
public ListNode reverse(ListNode head){
ListNode current = head;
ListNode previous = null;
while(current!=null) {
ListNode temp = current.next;
current.next = previous;
previous = current;
current = temp;
}
return previous;
}
答案 0 :(得分:3)
如果你被允许修改列表,那么有一个比我在评论中提到的空间更多的额外空间的更好的解决方案:
找到中间人。
从中间向右反转列表。
通过逐步完成两个列表来执行减法。
再次反向/加入列表以获取原始列表顺序。
所有这些步骤都需要O(1)空间和O(n)时间,因此整个算法也需要O(1)空间和O(n)时间。
这只是算法的概要,以证明在O(n)时间内可以使用常量额外空间,有一些陷阱,如奇数/偶数元素等。
可能还有一些改进空间,但你不能比O(n)时间更好,因为找到最后一个元素或执行减法已经需要O(n)时间。
答案 1 :(得分:2)
您可以编写一个递归函数来解决此问题而无需额外空间,即如果您不将堆栈帧视为额外空间。
代码是用C#编写的,但您应该能够轻松地将其翻译成您需要的语言。
这种方法的一个警告是,您需要使用全局变量跟踪我们当前的节点。
static ListNode<int> temp = list.head; // Point to first element in the list
private static int reverse(ListNode<int> listNode, int currentNode, int totalNodes)
{
if (listNode == null)
{
return 0;
}
currentNode = reverse(listNode.next, currentNode, totalNodes + 1);
if (currentNode < totalNodes) //To check if half is reached
{
temp.data = listNode.data - temp.data;
temp = temp.next;
}
return ++currentNode;
}
您可以调用此方法reverse(list.head, 0, 0);
并忽略返回值或将其存储在某个位置,因为它指向链接列表的中间位置,稍后可能会在某个位置使用。
通过链表的标准实现,我怀疑你是否能够比这更好地实现空间/时间复杂度。
如果您可以修改ListNode
的实现以包含该节点的索引,则可以替换全局变量并将其作为参数传递。