0
点赞
收藏
分享

微信扫一扫

算法练习-day4

青鸾惊鸿 2023-06-10 阅读 58

链表

24. 两两交换链表中的节点

题意:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即只能进行节点交换)

示例:

算法练习-day4_链表

       思路:本题其实和昨天链表反转非常类似,我们使用三指针的方法,按照一定的链表重构顺序即可完成一次相邻节点之间的交互。其次,我们需要注意:1.本题是两个相邻节点交互,例如,1->2->3->4,为1和2交互,3和4交互;但是,如果出现1->2->3,那么我们只需要交换1和2即可,无法匹配的节点不作改变。2.为了使返回时节点固定,因此我们可以创建一个头节点,返回的就是头节点的下一个节点,就不需要做额外标记了;并且在之后的重构中,头节点也能为我们省去代码。

C++代码:

    ListNode* swapPairs(ListNode* head) {
        ListNode* cur=new ListNode(0);//创建头节点
        cur->next=head;
        ListNode* rear=cur;//让一个节点代替cur向后移动
        while(rear->next&&rear->next->next)//这里就可以排除mid和front越界的情况
        {
            ListNode* mid=rear->next;
            ListNode* front=rear->next->next;
            mid->next = front->next;//链表重构的顺序不能变
            front->next = mid;
            rear->next = front;
            rear=mid;//只需要将开头节点改变即可
        }
        return cur->next;//此时返回的就是头节点的下一个节点
    }

19. 删除链表的倒数第 N 个结点

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

示例:

算法练习-day4_链表_02

       思路:先创建头节点,目的是为了将头结点的删除和其他节点删除同化为一种算法;其次是定义两个节点slow和fast,slow是需要删除节点的前一个节点,fast是用于计算slow走多少距离,两指针的距离就是链表中节点到nullptr的距离,这样在fast走到nullptr时,slow正好走到需要删除节点的前一个节点。

C++代码:

    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* cur=new ListNode(0);//创建一个头节点
        cur->next=head;
        ListNode* slow=cur;//用于记录需要删除节点的前一个节点
        ListNode* fast=head;//用于计算slow需要走动的距离
        while(n--)//计算好slow到节点的距离
        {
            fast=fast->next;
        }
        while(fast)//当fast为nullptr时,就说明slow走到了要删除节点的前一个节点
        {
            slow=slow->next;
            fast=fast->next;
        }
        slow->next=slow->next->next;
        return cur->next;
    }

面试题 02.07. 链表相交

题意:给你两个单链表的头节点headA和headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回null 。

示例:

算法练习-day4_链表_03

       思路:本题能想到两种思路,1.按照遍历数组的方式,找出两个数组相同的元素,此时就是两个for循环,以一条链表作为基准,从另一条链表中寻找是否有与该链表相交的节点,若有则直接输出相交节点;2.分别遍历两条链表,统计它们的节点个数,然后让长的链表起始位置向前移动,之后两指针分别向后移动,若出现相等地址,则说明两链表相交,返回即可。

方法1代码:

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* cur=headA;
        while(cur)//两次遍历,从A链表中找出与B链表相交的节点,并返回
        {
            ListNode* tmp=headB;
            while(tmp)
            {
                if(tmp!=cur)
                {
                    tmp=tmp->next;
                    continue;
                }
                return cur;
            }
            cur=cur->next;
        }
        return cur;//若找到nullptr还没有,则说明没有交点
    }

方法2代码:

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int sumA=0,sumB=0;
        ListNode* curA=headA;
        ListNode* curB=headB;
        while(curA)//算出两链表的节点大小
        {
            sumA++;
            curA=curA->next;
        }  
        while(curB)
        {
            sumB++;
            curB=curB->next;
        }
        curA=headA,curB=headB;
        if(sumA>sumB)//使两节点处于平等的起跑线
        {
            int poor=sumA-sumB;
            while(poor--)
            {
                curA=curA->next;
            }
        }
        else
        {
            int poor=sumB-sumA;
            while(poor--)
            {
                curB=curB->next;
            }
        }
        while(curA)
        {
            if(curA==curB)
            {
                return curA;
            }
            curA=curA->next;
            curB=curB->next;
        }
        return nullptr;
    }

142. 环形链表 II

题意:给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

示例:

算法练习-day4_链表_04

       思路:本题我有两种思路供大家参考:1.使用unordered_map记录每个指针出现次数,若出现次数等于2,则说明该指针指向的地址就是链表成环的入口,否则链表就不成环,返回nullptr;该方法的优点就在于代码量小,思路非常清晰。2.快慢指针法:定义两个指针fast和slow,规定fast一次走两格,slow一次走一格,直到它们相交,此时的交点并非起始位置,很有可能是环中的交点,这里我们画图说明:

算法练习-day4_链表_05

      此时可以算得:慢指针移动距离为X+Y,快指针移动距离为X+Y+n(Y+Z),由速度距离公式得:慢指针移动距离*2=快指针移动距离,因此X+Y=n(Y+Z)。我们需要得出X得距离,因此X=(n-1)(Y+Z)+Z;由于Y+Z是环得周长,因此当n=1时,X=Z。所有我们可以得出,当指针第一次相遇后,慢指针回到起点,两指针以相同的速度前进,再次相遇的地址就是环的入口。

方法1代码:

    ListNode *detectCycle(ListNode *head) {
        unordered_map<ListNode*,int> map;
        while(head)
        {
            map[head]++;
            if(map[head]==2)
            {
                return head;
            }
            head=head->next;
        }
        return nullptr;
    }

方法2代码:

    ListNode *detectCycle(ListNode *head) {
        if(head==nullptr||head->next==nullptr)
        {
            return nullptr;
        }
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow)//第一次相遇,这里也并不需要考虑为nullptr的情况,因此,如果快指针先为空,就说明该链表不成环
            {
                slow=head;//返回起点,此时快慢指针一起走,相遇的地方就是环的入口
                while(slow!=fast)
                {
                    fast=fast->next;
                    slow=slow->next;
                }
                return fast;
            }
        }
        return nullptr;
    }

举报

相关推荐

Day4

-day4

day4 QT

Qt day4

QT DAY4

hadoop——day4()

ARM day4 作业

Day4:录入、if、switch

0 条评论