(Leetcode)链表的slow,fast指针使用

本文介绍两种链表循环检测算法:快慢指针法判断循环存在与否及确定循环起点,以及链表重组算法实现链表元素的特殊重排。

141. Linked List Cycle

Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?

Code-Java

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode slow, fast;
        slow = fast = head;
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(slow==fast) return true;
        }
        return false;
    }
}

142. Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?

Code-Java

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head, slow = head;
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow){
                while(slow!=head){//fast和slow meet的node到环开始的node的距离s1,等于head到环开始的node的距离s2
                    head = head.next;
                    slow = slow.next;
                }
                return slow;
            }
        }
        return null;
    }
}

为什么 fast和slow meet的node到环开始的node的距离s1,等于head到环开始的node的距离s2?

Definitions:

cycle : length of the cycle, if exists.
start_dis : the distance from the head to Node_begin (the begin node of cycle).
meet_dis : the distance from Node_begin to the Node_meet(where slow and fast meet).
remaining_meet_dis : the distance from the Node_meet to Node_begin
we can see, meet_dis + remaining_meet_dis = cycle

Distance(slow) = start_dis + meet_dis + k1·cycle
Distance(fast) = start_dis + meet_dis + k2·cycle

 Distance(slow)*2 = Distance(fast)
=> start_dis + meet_dis = (k2-2k1)·cycle = k·cycle
=> start_dis = k·cycle - meet_dis = remaining_meet_dis

therefore, s1 = s2

143. Recorder List

Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…

You must do this in-place without altering the nodes' values.

For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.

Solution

1。利用slow、fast指针找到list的middle——O(n)
2。将middle之后的node翻转——O(n/2)
3。讲后面一半list插入前一半——O(n/2)
整个过程时间复杂度O(n),空间复杂度O(1)

Code

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void reorderList(ListNode head) {
        if(head==null || head.next==null || head.next.next==null) return;
        ListNode slow = head, fast = head;
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode middle = slow;
        ListNode pre  = slow.next;

        //reverse the half listnode after the middle
        while(pre.next!=null){
            ListNode cur = pre.next;
            pre.next = cur.next;
            cur.next = middle.next;
            middle.next = cur;
        }

        pre = head;
        //insert the reversed half into pre half
        while(middle.next!=null){
            ListNode cur = middle.next;
            middle.next = cur.next;
            cur.next = pre.next;
            pre.next = cur;
            pre = cur.next;
        }
    }
}
### LeetCode 链表题目 ACM模式 解题方 #### 了解ACM模式下的链表处理方式 在LeetCode平台,当采用ACM模式来解答链表相关的问题时,意味着提交的解决方案不仅限于函数定义部分,而是完整的程序文件。这通常包含了必要的头文件引入、`main()`函数以及输入输出逻辑的设计[^4]。 对于链表操作而言,在编写代码前理解其基本概念至关重要。例如,单向链表由节点组成,每个节点包含两部分内容:存储数据项的数据域和指向下一个节点地址指针域;双向链表则在此基础上增加了向前遍历的功能。为了高效地解决问题,熟悉如何创建新节点、连接或断开节点间的联系是非常重要的[^3]。 #### 完整的ACM模式链表问题求解框架 下面给出一个通用模板用于解决大多数基于C++语言编写的LeetCode链表类题目: ```cpp #include <iostream> using namespace std; // Definition for singly-linked list. struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; class Solution { public: // 主要算实现放在这里 }; int main() { // 输入读取与初始化工作 string input; cin >> input; // 将输入转换成链表形式或其他所需格式 // 调用Solution类的方并获取返回结果 // 输出最终答案到标准输出流cout中去 return 0; } ``` 此模板展示了从接收用户输入直到打印出计算结果的整体流程。其中具体业务逻辑需根据实际问题调整完善。 #### 实战案例分析——环形链表检测 作为实例之一,“环形链表”是一个经典面试题,它要求判断给定链表是否存在循环结构。一种有效策略是利用快慢指针(Floyd判圈算),即设置两个速度不同的指针同时沿着链表前进直至相遇,则表明存在闭环路径。 ```cpp bool hasCycle(ListNode *head) { if (!head || !head->next) return false; ListNode* slow = head; ListNode* fast = head->next; while (fast != nullptr && fast->next != nullptr){ if(slow == fast) return true; slow = slow->next; fast = fast->next->next; } return false; } ``` 上述代码片段实现了对链表是否有环这一特性的快速检验功能,并且能够很好地适应ACM竞赛环境的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值