Day 4 链表2

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

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/

答案链接:代码随想录

思路:

思路很简单,遍历链表,更换两两元素的位置。难点在于每次换位置的实现。

解答:

感悟:

(1)firstnode不可以移动。在第一遍做的时候,想到了用虚拟节点指向head,但是在遍历的时候,用虚拟节点firstnode进行移动,也就是变动了firstnode。这相当于链表的头一直在变。正确的做法是另声明一个变量cur,让cur = firstnode,之后移动cur

(2)步骤23错位。之前我的想法是先连cur-2,之后连1-3,最后连2-1。但是这个想法很不规范,可以先画出图来。

代码:

ListNode* swapPairs(ListNode* head) {
        ListNode * firstnode = new ListNode();
        firstnode->next = head;
        ListNode * tempnode = new ListNode();
        ListNode * lastnode = new ListNode();
        ListNode * cur = firstnode;
        while(cur->next!=nullptr && cur->next->next!=nullptr){
            lastnode = cur->next->next->next;
            tempnode = cur->next;
            cur->next = cur->next->next;
            cur->next->next = tempnode;
            tempnode->next = lastnode;
            cur = tempnode;
        }
        return firstnode->next;
    }

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

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目解答:代码随想录

思路:

 因为链表无法索引,所以我利用两次遍历的方式解决这个问题。第一次得到链表长度,第二次删除指定节点。

解答:

双指针。如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

感悟:

(1)如果创建虚拟节点dummyhead,返回head其实为return dummyhead->next。因为如果head发生变动,return head就没有意义了。而dummyhead是不会变的。

(2)可以利用双指针的方式,实现差额补位。(链表中最后一个节点不知道,但是双指针中快慢指针的差异可以弥补)

代码:

(1)二次搜索

ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *cur = head;
        int len = 0;
        while(cur!=nullptr){
            cur=cur->next;
            len+=1;
        }
        ListNode *dummyfirst = new ListNode();
        dummyfirst->next = head;
        int need_move = len - n;
        cur = dummyfirst;
        for(int i = 0; i<need_move; i++){
            cur = cur->next;
        }
        //ListNode *del = cur->next;
        cur->next = cur->next->next;
        //delete del;
        return dummyfirst->next;
    }

(2)双指针

ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *dummyhead = new ListNode();
        dummyhead->next = head;
        ListNode *fast = dummyhead;
        ListNode *slow = dummyhead;
        for(int i=0; i<n; i++){
            fast = fast->next;
        }
        while(fast->next!=nullptr){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return dummyhead->next;
    }

面试题02.07.链表相交

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

答案链接:代码随想录

思路:

这道题的难点还是在于链表长度不已知。因此,同样可以利用双指针法,每个链表一对双指针,先通过快指针让链表对齐,之后通过慢指针找到合并的位置。

这道题代码随想录中给的是二次遍历的方法,时间复杂度比我的高,空间复杂度比我的低。

代码:

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *fast1 = headA;
        ListNode *slow1 = headA;
        ListNode *fast2 = headB;
        ListNode *slow2 = headB;
        while(slow1 != nullptr && slow2 != nullptr){
            if (slow1 == slow2){
                return slow1;
            }
            if (fast1 == nullptr && fast2 != nullptr){
                fast2 = fast2->next;
                slow2 = slow2->next;
            }else if (fast2 == nullptr && fast1 != nullptr){
                fast1 = fast1->next;
                slow1 = slow1->next;
            }else if (fast1 == nullptr && fast2 == nullptr){
                slow1 = slow1->next;
                slow2 = slow2->next;
            }else{
                fast1 = fast1->next;
                fast2 = fast2->next;
            }
        }
        return NULL;
    }

142. 环形链表2

思路:

这道题的难点在于不知道如何判断是否进入循环,比较困难。

方法:

设计快慢指针。快指针追上慢指针,说明存在循环。之后通过数学计算得到循环口位置:

当快指针追上慢指针的时候:

(快指针走过:x+y+n*(y+z)) =2 * (慢指针走过:(x+y))

n*(y+z) = x + y

x = n*y - y + n*z

x = (n-1)*(y+z) + z

也就是说,从head发出一个指针1,从相遇点发出一个指针2,指针2会转n-1圈,之后走z与指针1相遇,这个时候,相遇点正好是环入口。

感悟:

(1)无限循环问题,可以用速度差进行识别

代码:

ListNode *detectCycle(ListNode *head) {
        ListNode *slowindex = head;
        ListNode *fastindex = head;
        ListNode *newindex = head;
        while(fastindex != nullptr && fastindex->next != nullptr){
            slowindex = slowindex->next;
            fastindex = fastindex->next->next;
            if(slowindex == fastindex){
                while(newindex != slowindex){
                    newindex = newindex->next;
                    slowindex = slowindex->next;
                }
                return slowindex;
            }
        }
        return NULL;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值