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

想法:链表题再练习

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

想法:两两交换,移动搜索指针进行,需要注意边界判断

阅读后想法:虚拟节点很方便,由于我们在交换的过程中,会丢失对head的指向,通过一个虚拟节点来避免这个问题的发生

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* newHead = new ListNode(-1);
        newHead->next = head;
        ListNode* cur = newHead;
        while(cur->next!=nullptr && cur->next->next!=nullptr) {
            ListNode* next = cur->next;
            cur->next = cur->next->next;
            next->next = cur->next->next;
            cur->next->next = next;
            cur = next;
        }
        return newHead->next;
    }
};

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

想法:有两个做法,一种遍历链表,计算出链表长度,进行加减运算;一种,先反转链表,删除后,再反转;突然又有个想法,用双指针,fast指针先走n步,再跟slow指针同时走,当fast走到空的时候,slow就是对应的

阅读后想法:同样为了避免头节点丢失,使用虚拟头节点

思路:找到需要删除节点的前一节点,通过两个指针一起移动来定位到

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* newHead = new ListNode(-1);
        newHead->next = head;
        ListNode* fast = newHead;
        ListNode* slow = newHead;
        while(n--) {
            fast = fast->next;
        }
        while(fast->next!=nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return newHead->next;
    }
};

面试题 02.07. 链表相交

想法:一种是用set数据结构,保存节点,判断是否相遇;但是这题是面试题,需要考虑空间复杂度,因此可以通过遍历两个链表,求出长度差值,长链表先移动差值,再同时移动

a. 如果笔试出现 (时间复杂度优先)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_set<ListNode*> myset;
        ListNode* cur = headA;
        while(cur!=NULL) {
            myset.insert(cur);
            cur = cur->next;
        }
        cur = headB;
        while(cur!=NULL) {
            if(myset.find(cur)!=myset.end()) {
                break;
            }
            cur = cur->next;
        }
        return cur;
    }
};

b. 如果面试出现 (考虑空间复杂度)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* cur = headA;
        int size = 0;
        while(cur!=NULL) {
            size++;
            cur = cur->next;
        }
        cur = headB;
        while(cur!=NULL) {
            size--;
            cur = cur->next;
        }
        ListNode* fast = size>0?headA:headB;
        ListNode* slow = fast==headA?headB:headA;
        size = abs(size);
        while(size--) {
            fast = fast->next;
        }
        while(fast!=NULL) {
            if(fast==slow) {
                return fast;
            }
            fast = fast->next;
            slow = slow->next;
        }
        return NULL;
    }
};

142.环形链表II

想法:两种想法,一种是通过set,一种是通过两个指针,一个走一步,一个走两步(规律),由于需要返回入环节点,因此当相遇以后,快指针回到头节点初,再次相遇则成

a. 笔试题

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode*> myset;
        ListNode* cur = head;
        while(cur!=NULL) {
            if(myset.find(cur)!=myset.end()) {
                return cur;
            }else {
                myset.insert(cur);
                cur = cur->next;
            }
        }
        return NULL;
    }
};

b. 面试题

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(true) {
            if(fast==NULL || fast->next==NULL) {
                return NULL;
            }
            fast = fast->next->next;
            slow = slow->next;
            if(fast==slow) {
                break;
            }
        }
        fast = head;
        while(fast!=slow) {
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

总结:

链表题目主要是双指针,虚拟头节点的应用,或者说创建多个节点的指向,在这个过程中需要注意关于指针丢失,提前存好位置等

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值