LeetCode算法题——删除链表的倒数第N个节点

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

示例:

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

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

给定的 n 保证是有效的。

进阶:

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

思路: 定义两个指针,先移动右指针使两个指针间隔固定长度n,然后将两个指针同步移动到链表最后的节点。最后删除左指针的下一个节点即可。
坑: 考虑到边界情况,即删除的节点是链表的第一个节点或者最后一个节点。第一个节点没有前驱节点,由于要确定删除第一个节点实现和所有的其他情况统一化,解决办法是在链表的头部添加一个前置的节点。

第一次写的代码:

/**
 * 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) {
        if (!head->next)
        {
            head = head->next;
            return head;
        }
            
        ListNode* left = head;
        ListNode* right = head;
        int curr_idx = 0;
        while( right->next ){
            right = right->next;
            curr_idx ++;
            if( curr_idx > n ){
                left = left->next;
            }
        }
        if (curr_idx == 1)
        {
            if (n == 1)
            {
                head->next=NULL;
                delete(right);
                return head;
            }
            if (n == 2)
            {
                head = head->next;
                return head;
            }
            
        }
        if (curr_idx == 2)
        {
            if (n == 1)
            {
                right =  right->next;
                delete right;
                
            }
            if (n == 2)
            {
                ListNode* m = head->next;
                m->val=m->next->val;
                m->next=m->next->next;
                return head;
            }
            if (n == 3)
            {
                head = head->next;
                return head;
            }
        }
        if (curr_idx == n-1)
        {
            head = head->next;
            return head;
        }
        left->next = left->next->next;
        return head;
    }
};

优化后的代码:

/**
 * 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 *pre = new ListNode(0);
        pre->next = head;
        ListNode *right = pre;
        ListNode *left = pre;

        for(int i = 0; i < n; i++) {
            right = right->next;
        }
        while(right->next != NULL) {
            right = right->next;
            left = left->next;
        }

        ListNode *k = left->next;
        if(k == head) {
            head = head->next;
            delete k;
            return head;
        }
        left->next = k->next;
        delete k; 

        return head;
    }
};

总结:
1、删除一个节点的关键是找到该节点的前向节点
2、头节点没有前向节点,就人为的添加一个前向的节点,这样可以使处理所有的情况实现统一,而不用因处理特殊情况引入复杂的开销。

你可能感兴趣的:(LeetCode解题)