优美编程

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

2020-01-17  本文已影响0人  小遁哥

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

示例:

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

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

给定的 n 保证是有效的。

进阶:

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

链表的结构是这样的

1解法

链表的结构是这样的

let ListNode = {
  val: 1,
  next: {
    val: 2,
    next: {
      val: 3,
      next: null,
    },
  },
};

分情况处理

var removeNthFromEnd = function(head, n) {
    
    let list = [head];
    
    let node = head;
    while(node.next){
        
        node = node.next;
        list.push(node);
    }
    if(list.length === 1){
        //只有一个
        return null;
    }
    let pos = list.length - 1  - n;
    if(pos === -1 ){
        //删除第一个
        list[0].val = list[0].next.val;
        list[0].next = list[0].next.next;
    }
    else if(n === 1){
        //删除最后一个
        list[pos].next = null;
    }
    else{
         //中间接口
         list[pos].next = list[pos].next.next;
    }
 
    return head;
    
};

找到要删除节点的上一个节点。
通过next属性将每一个节点分离出来=>放入数组
在分删除第一个、删除最后一个、删除中间的、只有1一个的情况 分别处理

不转化为数组

var removeNthFromEnd = function(head, n) {
  const dummy = {
      next: head,
  };
  let slowP = dummy;
  let fastP = dummy.next;
  while (n && fastP) {
      n--;
      fastP = fastP.next;
  }
  while (fastP) {
      slowP = slowP.next;
      fastP = fastP.next;
  }
  slowP.next = slowP.next.next;
  return dummy.next;
};

上面解法的精髓在于,既然我们想要删除一个节点就要找到上一个节点,直接在前面加一个节点,这样就不用考虑一些特殊情况

第二点,以a=>b=>c=>d=>e为例,想要删除d这个元素,也就是倒数第2个,p向前走2步到b,此时距离p走到e还有3,此时q一起走3步 ,就找到了c,这是就可以通过c删除d了

可以通过一次while循环搞定

var removeNthFromEnd = function(head, n) {
  if (!head) return null;
  let tmp = { next: head };
  let p = tmp,
    q = tmp;
  let count = 0;
  while (q.next) {
    if (count < n) {
      count++;
      q = q.next;
    } else {
      p = p.next;
      q = q.next;
    }
  }
  p.next = p.next.next;
  return tmp.next;
};

2结语

最初的解法一开始并没有考虑到全部的情况

看来好的算法可以减少逻辑错误,尽量利用数据结构自身的特点去解决问题是优化算法的不二法则。

上一篇下一篇

猜你喜欢

热点阅读