LeetCode 探索初级算法-链表:22 删除链表的倒数第N个节点-20200405

LeetCode探索初级算法目录


22 删除链表的倒数第N个节点-20200405

题目

给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

示例

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明

给定的 n 保证是有效的。

进阶

你能尝试使用一趟扫描实现吗?


注意事项

  1. 链表并不是list和字典,这是一种自定义的数据结构,所以当没有给出相应的方法时,需要自己写遍历。
  2. 这里要删除的是倒数的第N个元素,所以要注意,开始只给了head节点,没有给出整个链表的长度。

思路一
先遍历找出数组长度,然后再循环把倒数第n个元素跳过去。

修改经历:

1. 超出时间限制。。。为什么呢?(第一次提交)

  • 超出时间限制

2. 找出了问题,在第一个循环之前将temp=head,但是循环的时候操作时,temp=head.next。这样的操作会一直迭代。(第二次提交)

  • 解答错误

3. 由于对链表的不熟悉,导致在第二次循环的时候当i==length-n时,head=head.next.next。这里要注意一点的是,python中的等号赋值相当于浅拷贝,所以临时变量的操作对原链表的操作。还有,操作时是让前一个的指针跳过当前节点指向下一个节点,而查询的时候是让节点逐个后移。(第三次提交)

  • 解答错误

4. 没有考虑到输入为[1,2]和2的情况,此时的输出应该为[2]。(第四次提交)

  • 执行用时 :40 ms, 在所有 Python3 提交中击败了60.18%的用户
  • 内存消耗 :13.7 MB, 在所有 Python3 提交中击败了6.54%的用户

心得体会:

在 temp=head时,一定要区分 temp=temp.next 和 temp.next = temp.next.next 的区别。

前者可以理解为查询,对原链表不操作。

后者改变了链表结构,所以head的结构也变化了。

还有理解temp和head代表的只是一个节点,next里存的是下一个节点的地址。

最终代码展示:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        length = 1
        tempHead = head
        while tempHead.next:
            tempHead = tempHead.next
            length += 1
        if length-n == 0:
            return head.next
        else:
            target = head
            for i in range(0, length-1):
                if i == (length-n-1):
                    target.next = target.next.next  # 在操作时是把指针串起来
                    break
                else:
                    target = target.next  # 在指向的时候是用下一个节点代替当前节点
        return head

思路二

官方给出的一次遍历的思路,双指针的方法。通过让两个指针中间间隔n个节点,使得当前一个指针到达末尾时,后一个指针正好落在要删除的元素上。同时引入一个哑结点来防止出现特殊情况。

修改经历:

1. 返回的时候写的是head,但是在输入为[1]和1时,会报错。预计是[],但是输出为[1]。(第一次提交)

  • 解答错误

2. 将 return head 为 return dummyNode.next。因为两指针都是dummyNode来的。(第二次提价)

  • 执行用时 :44 ms, 在所有 Python3 提交中击败了42.32%的用户
  • 内存消耗 :13.8 MB, 在所有 Python3 提交中击败了6.54%的用户

心得体会:

这种方法还是很好地,提前找到提前量。尤其是哑结点 dummyNode 设计的很妙,避免了第一次提交的错误。

最终代码展示:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummyNode, counter = ListNode(-1), 0
        dummyNode.next = head
        fP, lP = dummyNode, dummyNode
        while fP.next != None:
            if counter < n:
                fP = fP.next
            else:
                fP = fP.next
                lP = lP.next
            counter += 1
        lP.next = lP.next.next
        return dummyNode.next

思路三

递归迭代。设置一个全局变量,先通过递归找到链表的最后一个,然后递归输出,输出一次全局变量加一。当全局变量不为n时,输出当前节点;当全局变量为n时,输出为下一个节点。相当于倒着链接链表,当遇到要删除的元素时,就直接跳过去,让上一个节点连接到下一个去。

大神就是大神!

这个就直接贴代码了,反正我一时半会是写不出来的。

最终代码展示:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        global i 
        if head is None:
            i=0
            return None
        head.next = self.removeNthFromEnd(head.next,n)
        i+=1
        return head.next if i==n else head

上一篇:LeetCode 探索初级算法-链表:21 删除链表中的节点-20200404

你可能感兴趣的:(LeetCode,探索初级算法)