一、题目
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
二、解题
方法一:
将链表中的所有元素存入数组,然后在找到倒数第n个节点,将其删除。具体代码见removeNthFromEnd2().时间复杂度为O(n),空间复杂度为O(n).
方法二:
使用两个指针,相当于一个尺子,尺子的长度为n,右边是first,左边是second,然后同时移动,当first移动到最后一个节点,此时second所在的位置就是倒数第n个节点。然后删除该节点即可。具体代码见removeNthFromEnd().时间复杂度为O(n),空间复杂度为O(n).
从算法上看,方法二最优.
三、代码实现
class Solution {
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
var first: ListNode? = head
var second: ListNode? = head
for _ in 0..<n {
first = first?.next
}
// 如果first为nil,说明倒数第n个,就是第一个直接返回head?.next
if first == nil {
return head?.next
}
while first?.next != nil {
first = first?.next
second = second?.next
}
second?.next = second?.next?.next
return head
}
func removeNthFromEnd2(_ head: ListNode?, _ n: Int) -> ListNode? {
if head == nil {
return nil
}
var next: ListNode = head!
var arr: [ListNode] = [next]
while next.next != nil {
arr.append(next.next!)
next = next.next!
}
let i = arr.count - n
if i == 0 {
return i+1 < arr.count ? arr[i+1] : nil
}else if i > 0 {
arr[i-1].next = i+1 < arr.count ? arr[i+1] : nil
}
return head
}
}
public class ListNode : CustomStringConvertible{
public var val: Int
public var next: ListNode?
public init(_ val: Int) {
self.val = val
self.next = nil
}
public var description: String {
var str = "\(val)"
var next = self
while next.next != nil{
str += "->\(next.next!.val)"
next = next.next!
}
return str
}
}
Demo地址:github