代码随想录#4

链表part02

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

主要是要厘清交换的顺序,主要有三个步骤,由于其中的交换和前后关系非常复杂,会需要使用到两个临时存储节点值的变量,在这个过程中容易迷糊。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* cur = dummyHead;
        while(cur->next != nullptr && cur->next->next !=nullptr){
            ListNode* tmp = cur->next;
            ListNode* tmp1 = cur->next->next->next;

            cur->next = cur->next->next;
            cur->next->next = tmp;
            cur->next->next->next = tmp1;

            cur = cur->next->next;
        }
        ListNode* result = dummyHead->next;
        delete dummyHead;
        return result;
    }
};

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

可以理解为像滑动窗口一样,将n个节点这个窗口整个从最前端移动到末尾,那么后面那个指针指向的位置就是需要删除的位置的前一个。这种思路的原因应该是链表的数据结构特殊,不方便从尾巴往前进行遍历,所以可以采用这种移动窗口的方式。

还需要注意,一定是最后的后面那个指针指向需要删除的前一个位置。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;

        while(n-- && fast!=NULL){
            fast = fast->next;
        }
        fast = fast->next;
        while(fast!=NULL){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return dummyHead->next;
    }
};

感觉这种利用快慢指针滑动窗口的方式非常神奇,值得反复琢磨和学习,在一些情形下会有妙用。

3.链表相交面试02.07.

首先因为链表是有前后顺序的存储结构,所以有相交的节点一定是后半部分,这时候需要将两个链表后边的部分对齐,然后从对齐位置的开头开始找,遍历就能够找到相交的位置。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while(curA != NULL){
            lenA++;
            curA = curA->next;
        }// 求链表A的长度
        while(curB!=NULL){
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        if(lenB>lenA){
            swap(lenA,lenB);
            swap(curA,curB);
        }
        int gap = lenA-lenB;
        while (gap--){
            curA = curA->next;
        }
        while (curA!=NULL){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }

};

主要是要认识到后端对齐然后从对齐的开头开始往后遍历的点,明白这个点就可以大致得到结果了。

4.环形链表Ⅱ142

首先要想明白怎么判断链表中间是否有环,跟指针有关可以想到快慢指针的使用,快指针往前走两步,慢指针往前走一步,最后两个指针一定会在环里相遇,如果没有相遇就说明没有环存在。

这块其实还是挺好理解的,相当于两者有一个速度差。

然后就需要找到环的入口,这部分需要结合讲解理解一下,跟推导相遇问题很像,把每个过程的未知量设出来然后计算一下,能够的出来从相遇的点出发一个指针,从开头出发一个指针,这两个指针相遇的位置就是环的入口。

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

总结

链表是一个相对来说比较复杂的数据结构,需要仔细分析前后关系,在处理其中节点的时候也要注意操作的出发点。在具体设计代码的时候需要仔细盘算一下结构。感觉这部分有时间还要回顾一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值