数据结构-链表问题

本文探讨了在算法练习中遇到的链表问题,包括单链表的中点查找、翻转、删除节点、合并链表、回文判断、环形链表检测与入环节点定位,以及判断链表是否相交和求交点的方法。重点介绍了快慢指针的应用和链表操作的思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在算法练习中遇到的链表问题
单链表

1.快慢指针找中点或者某一个位置

class Solution {
public:
    bool isPalindrome(ListNode* head) {
          ListNode* slow = head, *fast = head,  *prev = nullptr;
        //快慢指针:使fast指针的前进速度为slow指针的前进速度的两倍,当fast指到链尾时,slow指针就指到链表中间结点
         while (fast  && fast->next ){//find mid node
        slow = slow->next;   
       fast=fast->next->next;
    }
        

2.链表翻转

class Solution {
public:
    ListNode* reverseList(ListNode* head) {

    ListNode *p = head;//当前指针节点
    ListNode *pre = NULL;//前指针节点
    while (p!=NULL) {    //循环都将当前节点指向它前面的节点,然后当前节点和前节点后移
      
        ListNode* nxt = p->next;//临时节点,暂存当前节点的下一节点,用于后移
        p->next = pre;//将当前节点指向它前面的节点
        pre=p;//前指针后移
        p=nxt; //当前指针后移
    }
    return pre;
    }
};

3 删除链表中的节点
思路:让要删除的节点的值等于下一个节点的值,删除之后的节点。(因为,我们无法访问我们想要删除的节点 之前 的节点,我们始终不能修改该节点的 next 指针。相反,我们必须将想要删除的节点的值替换为它后面节点中的值,然后删除它之后的节点。*)

class Solution {
public:
    void deleteNode(ListNode* node) {
        node->val = node->next->val;
        node->next = node->next->next;    //修改指针语句—— 链表删除
    }
};

4.合并链表(1.首尾相连合并链表 2.顺序合并链表)

2.顺序合并链表
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1==NULL)
            return l2;
        if(l2==NULL)
            return l1;
    
          ListNode* pa = l1; 
          ListNode* pb = l2;    
        ListNode *l3 = new ListNode(NULL);
        ListNode* pc = l3; 
        while(pa&&pb)
        {
            if(pa->val <= pb->val)
            {
                pc->next = pa;
                pc=pa;
                pa=pa->next;  
            } 
            else  
            {
                pc->next = pb;
                pc=pb;
                pb=pb->next;}
        }
        pc->next = pa?pa:pb;
        return l3->next;
    }
};

5.回文链表
思路:
//其一,find mid node 使用快慢指针找到链表中点。
//其二,reverse 逆序后半部分。
//其三,check 从头、中点,开始比较是否相同。


class Solution {
public:
    bool isPalindrome(ListNode* head) {
          ListNode* slow = head, *fast = head,  *prev = nullptr;
        //快慢指针:使fast指针的前进速度为slow指针的前进速度的两倍,当fast指到链尾时,slow指针就指到链表中间结点
         while (fast  && fast->next ){//find mid node
        slow = slow->next;   
       fast=fast->next->next;
    }
        while (slow){//reverse
        ListNode* ovn = slow->next;
        slow->next = prev;
        prev = slow;
        slow = ovn;
    }
        while (head && prev){//check
        if (head->val != prev->val){
            return false;
        }
        head = head->next;
        prev = prev->next;
    }
        return true;   
    }
};

6.环形链表(链表中是否有环)****

//141.环形链表
//思路:快慢指针,如果慢指针追上快指针则表示有环 返回true  追不上怎表示没环
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode *p = head;
        ListNode *q = head;
        ListNode * nu = NULL;
        while(p && p->next)
        {
            p = p->next->next;
            q = q->next;
            if(q == p)
            {
                return true;
            }
        }
        
        return false;
        
        
    }
};

7.找到入环节点
常见的方法是:在确定链表有环之后,慢指针重新指向链表头,快指针留在相遇处;然后快慢指针再以每次移动1个节点的速度前进,最终他们在入环节点相遇。
在这里插入图片描述
如图,设整个链表长度为L,环长度为R,且距离具有方向性,例如CB是C点到B点的距离,BC是B点到C点的距离,CB!=BC。当证明有环时,fast和slow都顺时针到了B点,则此时:
slow走的距离:AC+CB
fast走的距离:AC+kR+CB(k=0,1,2…)
由于fast每次走2个节点,slow每次走1个节点,所以:
2(AC+CB) = AC+k
R+CB
AC+CB = k*R
AC+CB = (k-1)*R+R
AC = (k-1)*R+R-CB
AC = (k-1)*R+BC
从最终的表达式可以看出来,AC的距离等于绕环若干圈后再加上BC的距离,也就是说慢指针从A点出发以速度1前进、快指针从B点出发以速度1前进,则慢指针到C点时,快指针也必然到了。

function ListNode(x){
    this.val = x;
    this.next = null;
}
function EntryNodeOfLoop(pHead){
    if(pHead === null)
        return null;
    var fast = pHead;
    var slow = pHead;

    while(fast.next !==null && fast.next.next !== null) {
        slow = slow.next;
        fast = fast.next.next;
        if(slow === fast)
            break;
    }

    if(fast === null || fast.next === null)
        return null;
    // 有环,slow重新回到链表头
    slow = pHead;
    
    // slow和fast重新相遇时,相遇节点就是入环节点
    while(slow !== fast) {
        slow = slow.next;
        fast = fast.next;
    }

    return slow;
}

8、判断两个链表是否相交
两种情况:A;有环
B;没环
A:在环里设置一个指针不动,另一个从头开始移动,指针相遇则相交。
B:判断两个链表最后节点是否相同,相同即相交。

9、 两个链表相交,求交点。
在这里插入图片描述
解法1.用两个stack栈
解法2,求出两个链表长度a,b,一个指针从head开始,一个从head+|a-b|开始,相遇即相交。求出交点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值