代码随想录算法训练营第四天| 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点 ,142.环形链表II

Leetcode 24. 两两交换链表中的节点
思路分析:
本题可用递归法或迭代法求解。主要是弄清楚两个节点更新一次,交换的可用next指针间隔指向处理。

代码实现:
递归法:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* cur_node = head;
        if (cur_node==nullptr || cur_node->next==nullptr) {
            return cur_node;
        }
        ListNode* next_node = cur_node->next;
        cur_node->next = swapPairs(next_node->next);
        next_node->next = cur_node;
        return next_node;
    }
};

迭代法:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur_node = dummy;
        while (cur_node->next && cur_node->next->next) {
            ListNode* tmp_1 = cur_node->next;  // cur_node,cur_node->next,cur_node->next->next节点后面会被改变,需要提前保存
            ListNode* tmp_2 = cur_node->next->next->next;
            cur_node->next = cur_node->next->next;
            cur_node->next->next = tmp_1;
            cur_node->next->next->next = tmp_2;
            cur_node = cur_node->next->next; // 两个节点更新一次
        }
        return dummy->next;
    }
};

Leetcode 19.删除链表的倒数第N个节点
思路分析
直观的解法可以先统计链表的长度,方便正向处理链表。如果n和链表长度相等,则返回原始链表的第一个结点。其他情况可采取倒数n+1结点的next指向第n-1个结点(即覆盖)。
参考《代码随想录》,可以更巧妙地使用快慢指针(双指针)法,让fast指针先走n+1步,然后fast和slow同步走,等fast指向nullptr时,slow指针即只想待删除的倒数第N个节点的上一结点,然后用slow->next指向slow->next->next,即可实现删除倒数第N个节点的结果。
代码实现
方法一:统计链表长度,正向删除对应结点

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        int len = 0;
        int count = 0;
        ListNode* cur_node = head;
        while (cur_node != nullptr) {
            len++;
            cur_node = cur_node->next;
        }
        if (n == len) {
            return head->next;
        }
        ListNode* tmp_node = head;
        while (tmp_node != nullptr && tmp_node->next != nullptr) {
            count++;
            if (count == len - n) {
                tmp_node->next = tmp_node->next->next;
            } else {
                tmp_node = tmp_node->next;
            }
        }
        return head; 
    }
};

方法二:快慢指针(双指针)法

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        while(n-- && fast != nullptr) {
            fast = fast->next;
        }
        fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
        while (fast != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next; 
        return dummyHead->next;
    }
};

Leetcode 142.环形链表II
思路分析
本题首先需要确定链表中是否存在环,其次是找到入环的节点。可以实现快慢指针(双指针)法,如果fast和slow节点能相遇,则说明该链表中存在环,反之亦真。
然后根据快慢指针行驶速度和相遇的特征,可以分析出:从相遇节点和从head节点到入环节点的步数是一样的,因此可再建立双指针tmp1和tmp2,tmp1和tmp2相遇的节点即为入口节点。
代码实现

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast_node = head;
        ListNode* slow_node = head;
        ListNode* meeting_node = nullptr;
        ListNode* entrance_node = new ListNode(0);
        while (fast_node!=nullptr && fast_node->next!=nullptr) {
            fast_node = fast_node->next->next;
            slow_node = slow_node->next;
            if (fast_node == slow_node) {
                meeting_node = fast_node;
                ListNode* tmp1 = head;
                ListNode* tmp2 = meeting_node;
                while (tmp1 != tmp2) {
                    tmp1 = tmp1->next;
                    tmp2 = tmp2->next;
                }
                entrance_node = tmp1;
                return entrance_node;
            }
        }      
        if (meeting_node == nullptr) {
            return nullptr;
        } else {
            return entrance_node;
        }
    }
};

你可能感兴趣的:(代码随想录训练营,链表,算法,数据结构)