LeetCode题解:(19) Remove Nth Node From End of List

题目说明

Given a linked list, remove the nth node from the end of list and return its head.
For example,

Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:
Given n will always be valid.
Try to do this in one pass.


题目分析

看上去还挺简单的,由于题目要求只遍历一遍链表,我的做法是采用两个指针,保证两个指针的距离为n,这样当前面的指针到达尾部的时候,另一个指针的位置就是要移除的结点。

以下为个人实现(C++,糟糕的一坨代码):

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *new_head = new ListNode(-1);
        new_head->next = head;
        ListNode *p1 = new_head, *p2 = new_head;
        for (int i = 0; i <= n; i++, p2 = p2->next); // p2 = p1 + n + 1
        for (; p2 != NULL; p2 = p2->next, p1 = p1->next);
        p2 = p1->next;
        p1->next = p2->next;
        delete(p2);
        p2 = new_head->next;
        delete(new_head);
        return p2;
    }
};

这里比较僵硬的一点是链表头的元素需要额外进行判断,我这种算法可以说很辣鸡了……

于是在讨论版看到了另外一种和我思路一样,但是细节不同的代码实现:

class Solution
{
public:
    ListNode* removeNthFromEnd(ListNode* head, int n)
    {
        ListNode** t1 = &head, *t2 = head;
        for(int i = 1; i < n; ++i)
        {
            t2 = t2->next;
        }
        while(t2->next != NULL)
        {
            t1 = &((*t1)->next);
            t2 = t2->next;
        }
        *t1 = (*t1)->next;
        return head;
    }
};

这份代码和我所实现的区别在于使用了二级指针,开始觉得很莫名其妙,后来看了Linus:利用二级指针删除单向链表的解释后,感觉这种做法挺巧妙的。

在第一种方法中(不使用二级指针),我所做的操作是将entry->next赋值给prev->next,然而当entry为链表头的时候就没有prev->next可以赋值了。但是实际上,任何一个链表都会有一个和prev->next同等地位的指针,那就是head指针,对于链表头元素,执行的操作可以是将head->next赋值给head。此时第二种方法(使用二级指针)的好处是它不关心entry->next究竟赋值给了谁,只关心赋值的地址,因此也免了判断entry是不是head的步骤了。

(微软笔试崩了……郁闷)

posted @ 2018-04-02 22:49  森高Slontia  阅读(129)  评论(0编辑  收藏  举报