Day4|Leetcode24. 两两交换链表中的节点 Leetcode19. 删除链表的倒数第 N 个结点 Leetcode面试题 02.07. 链表相交 Leetcode 142. 环形链表 II

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

题目链接 两两交换链表中的节点

本题还是对链表基础操作的考察,只不过进行了变形,还有些需要注意的点的;

首先是要对while中终止条件的思考,其次在交换节点时,注意顺序和对节点的数据进行提前记录,方便以后遍历。

下面直接用代码加注释的形式展现给大家:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        
            ListNode*dunnyhead = new ListNode(0);//定义一个虚拟头
            dunnyhead->next = head;//连接在head前
            ListNode*cur = dunnyhead;//cur指向虚拟头文件

            while(cur->next!=NULL&&cur->next->next!=NULL){//偶数时,满足第一个条件即可,奇数时,满足另一个条件即可
               //两个节点的值会改变,所以要将这两个节点值提前记录下来
                ListNode*temp = cur->next;
                ListNode*temp1 = cur->next->next->next;

                cur->next = cur->next->next;//dunnyhead和数字2连接起来
                cur->next->next = temp;//此时需要将数字2连接到数字1上,数字二现在是1节点,数字1变成了二节点
                temp->next = temp1;//数字1连接到数字3上即可
                cur = cur->next->next;//需要移动cur指针到第二个节点,为了方便后面的继续遍历和交换节点
            }
            return dunnyhead->next;//首节点
    }
};

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

题目链接19 删除链表的倒数第 N 个结点

本题目还是需要技巧,首先我们要删除倒数第n个节点,我们就要想到两个条件,第一个条件就是需要将指针指向删除节点的前一个,这样方便删除倒数第n个节点,第二个条件就是while停止条件是什么,解决这两个问题后本问题就很简单了,对于第一个问题,我们首先需要一个fast指针和一个slow指针,让fast先走n+1步,随后让slow和fast同时再走,当fast==NULL,你会发现slow指针刚好指在需要删除节点的上一位,很奇妙!画个图理解一下:

Day4|Leetcode24. 两两交换链表中的节点 Leetcode19. 删除链表的倒数第 N 个结点 Leetcode面试题 02.07. 链表相交 Leetcode 142. 环形链表 II_第1张图片

下面是代码和注释:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode*dunnyhead = new ListNode(0);//虚拟头节点
        dunnyhead->next = head;//建在head的前面
        ListNode*slow = dunnyhead;//快慢指针都放到虚拟头节点上
        ListNode*fast = dunnyhead;
        n++;//这里比较难想,首先第一个while是先让fast指针先走n+1步;
        //为了使slow指针指向需要删除节点的前一位,这样方便后续将删除节点删掉
        while(n--&&fast!=NULL){
            fast = fast->next;//遍历,让fast走n+1步
        }
        
        while(fast!=NULL){//当fast指向空时,说明此时slow已经走到删除节点的前一位了
            fast = fast->next;
            slow = slow->next;
            
        }
        
        slow->next = slow->next->next;//删除节点
        return dunnyhead->next;//结束
    }
};

Leetcode 面试题 02.07. 链表相交

题目链接 面试题 02.07. 链表相交

本题要审好题目,审准题目就解决问题了

再说一下做题的思路:

把两个链表的节点数算出,记录下两个链表的节点数差,这是为了让两个链接的指针保持到同一节点上,让两指针同时移动,直到移动到相同节点(数据)时就返回指针所指到的节点,否则就返回NULL

下面是代码加注释:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode*curA = headA;
        ListNode*curB = headB;
        int asize = 0;//节点数
        int bsize = 0;
        int csize = 0;//节点数差
        while(curA!=NULL){
            curA = curA->next;//计算a节点数
            asize++;
        }
        while(curB!=NULL){
            curB = curB->next;//计算b节点数
            bsize++;
        }
        curA = headA;//此时cur已经指向了节点末尾,要更新一下,将cur调到head
        curB = headB;
        if(bsize>asize){//这里是讨论到链表谁长的问题,要把长的放在前面
            swap(asize,bsize);
            swap(curA,curB);
        }
        csize = asize-bsize;
        while(csize--){//将长链表的指针调到和短链表的指针的同位置
            curA = curA->next;
        }
        while(curA!=NULL){//同时移动
            if(curA==curB){//节点相同返回该节点
                return curA;
            }
            curA = curA->next;//遍历
            curB = curB->next;
        }
        return NULL;
        
    }
};

Leetcode 142. 环形链表 II

题目链接 142 环形链表 II

本题目考察的不只是对环行链表的判断,还有对数学只是的一些渗透,基本的思想还是双指针,利用快慢指针来解决问题。首先我们需要判断是否为环链表,如何判断,我来解释一下:我们让fast指针每次移动两个节点,slow每次移动一个节点,同时从head开始移动,若不为环,slow指针永远追不到fast指针,若为环,结果两指针一定重合,原因是因为,fast相对于slow的速度为1,若两指针都在闭环中,相当于fast以每次一个节点的速度在靠近slow指针,重合时即证明了该链表是环链表。这是第一个问题,第二个问题就比较考验数学思维了,我们如何求环链表的入口节点,我用画图的形式来解释一下这个问题:

Day4|Leetcode24. 两两交换链表中的节点 Leetcode19. 删除链表的倒数第 N 个结点 Leetcode面试题 02.07. 链表相交 Leetcode 142. 环形链表 II_第2张图片

(图画的很丑,勿喷哈哈) 

这个问题就解决了,但是还有一些分歧,就是slow指针应该是2(x+y)+k(y+z){k为圈数},为什么不会有这种情况呢,因为当slow走了一圈时,fast已经走了两圈了,因为fast在环内追slow时相对速度是1,就不存在slow走了一圈,fast走两圈才相遇到的情况,只有fast走一圈,在环内追,刚进入环的slow的这一种情况。下面画个简图给大家看一下:

Day4|Leetcode24. 两两交换链表中的节点 Leetcode19. 删除链表的倒数第 N 个结点 Leetcode面试题 02.07. 链表相交 Leetcode 142. 环形链表 II_第3张图片

下面是代码加注释:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode*fast = head;//定义一个快指针,每次走两个节点
        ListNode*slow = head;//慢指针,每次走一个节点
        ListNode*index1 = fast;//index1,index2是为了判断环链表的入口
        ListNode*index2 = head;
        while(fast!=NULL&&fast->next!=NULL){//首先要保证在快指针移动下,找不到最后的一个节点,即证明是环的一个前提条件,也防止了空指针
            fast = fast->next->next;//fast走两步
            slow = slow->next;//slow走一步
            if(slow==fast){//如果两节点相遇,这是就已经证明了是环了
            //下面来求环链表的入口
                index1 = fast;
                index2 = head;
                while(index1!=index2){//这里可以看上面的公式理解
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;//返回入口值
            }
        }    
        return NULL;//否则返回空
    }
};

不早了,end 

你可能感兴趣的:(链表,数据结构)