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

24题主要时容易和翻转列表弄混,这题是需要虚拟头节点的,因为翻转第一对和第二对时的情况就不一样了,所以需要一个虚拟头结点,对于判断虚拟头结点的问题,看第一个和第二个的情况是否一致(自己理解)
另外是注意保存下一步所用到的节点,这个题思路简单,容易错就上面两个地方:
 

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

        ListNode* dummyHead = new ListNode(0);
        ListNode* cur = dummyHead;
        dummyHead->next = head;
        while (cur->next && cur->next->next) {
            ListNode* tmp = cur->next;
            ListNode* tmpNext = cur->next->next->next;
            cur->next = cur->next->next;
            cur->next->next = tmp;
            cur->next->next->next = tmpNext;
            cur = cur->next->next;
        }
        return dummyHead->next;
    }
};

19题删除倒数节点,首先考虑是删除节点那么最好还是用虚拟头结点,因为删除第一个和后面的节点情况不一样,自己先按照笨方法做了一下,fast指针先移动到最后,再计算slow指针所移动的距离:
 

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {

        ListNode* dummyNode = new ListNode(0);
        dummyNode->next = head;
        ListNode* cur = dummyNode;

        int fastIndex = 0;

        while (cur) {
            fastIndex++;
            cur = cur->next;
        }
        if (n <= 0 || n >= fastIndex)
            return head;
        int slowIndex = fastIndex - n - 1;
        cur = dummyNode;
        while (slowIndex--) {
            cur = cur->next;
        }

        cur->next = cur->next->next;
        return dummyNode->next;
    }
};

双指针一遍遍历的方法更高效点,注意while(fast),最后执行完的fast是末尾的空指针,slow直接落到要删除的node上,所有用while(fast->next)
 

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {

        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* fast = dummyhead;
        ListNode* slow = dummyhead;

        while (n--) {
            fast = fast->next;
            if (fast == nullptr)
                return head; // 如果 n 大于链表长度,直接返回原链表
        }
        while (fast->next) {
            fast = fast->next;
            slow = slow->next;
        }

        slow->next = slow->next->next;
        return dummyhead->next;
    }
};

链表相交主要将链表对齐后再遍历,因为假设有共同的尾巴,那么从尾巴往前捋比较方便:

 

class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {

        int sizeA = 0;
        int sizeB = 0;

        ListNode* curA = headA;
        ListNode* curB = headB;

        while (curA) {
            sizeA++;
            curA = curA->next;
        }

        while (curB) {
            sizeB++;
            curB = curB->next;
        }
        int length;
        if (sizeA > sizeB) {
            curA = headA;
            curB = headB;
            length = sizeA - sizeB;
        } else {
            curA = headB;
            curB = headA;
            length = sizeB - sizeA;
        }

        while (length--) {
            curA = curA->next;
        }

        while (curA) {
            if (curA == curB) {
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }

        return NULL;
    }
};

最后一个环形链表。我实在是不解为什么要按照数学推理来做,面试的时候哪有这个时间思考,本质就是找一个node有没有重复出现,用哈希不更好吗?用一个set或者map存储遍历过的node,如果再一次遍历到该node那就找到入口了,哈希yyds
 

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值