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

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

这道题的思路重点在于怎样交换两个节点,因为题目中强调了不可以改变节点的值,所以只能依靠改变节点的next的指向来改变节点的顺序,这里可以使用虚拟头指针可以更好地解决本题,移动来拿过几点的思路是先将虚拟头指针的next指向第二个节点再讲第二个的指针,再讲原第二个节点的next指向原第一个节点最后将原第一个节点指向原第三个节点。

 这样移动就完成了,接下来考虑循环的条件,因为需要移动两个节点所以只需要考虑这两个节点是否为空节点即可(因为所用到的第三个节点在只有两个节点是是空,也就是第二个节点指向的null,所以经过移动过程后并不影响结果),最后级的跟新cur的位置继续向后遍历。

/**
 * 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* dummynode = new ListNode(0);
        ListNode* cur = dummynode;
        dummynode -> next = head;
        while(cur -> next && cur -> next -> next){
            ListNode* tmp = cur -> next;
            ListNode* tmp1 = cur -> next -> next -> next;
            cur -> next = cur -> next -> next;
            cur -> next -> next = tmp;
            tmp -> next = tmp1;
            cur = cur -> next -> next;
        }
        return dummynode -> next;
    }
};

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

这道题可以用到之前解决数组问题时用到的双指针思想来解决,之前拿到数组的题我有拿出来琢磨了一下,那道题是要求移除目标元素并且不适用额外的空间,所有就需要使用swap将目标元素与非目标元素位置调换为了使数组的左边全部为非目标元素右边全部为目标元素,二这道题也是双指针但位置不同,这道题两指针的初始位置相同,fast指针先出发向前走n步,接着两指针一起向后遍历,直到fast->next == null,所以可以使用两个while循环,第一个循环控制fast指针移动n步,第二个循环控制两指针遍历整个链表。

/**
 * 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* dummynode = new ListNode(0);
        dummynode -> next = head;
        ListNode* fast = dummynode;
        ListNode* slow = dummynode;
        int i = 0;
        while(i <= n && fast){
            fast = fast -> next;
            i++;
        }
        while(fast){
            fast = fast -> next;
            slow = slow -> next;
        }
        slow -> next = slow -> next -> next;
        return dummynode -> next;
    }
};

这道题我有两个点出错了,一个是当需要删除head节点时的情况出错因为未使用虚拟头结点,第二点是因为在移动指针时循环条件除了要注意走的步数以外还要判断fast是否为空指针。

Leetcode-02.07 链表相交

这道题一开始未读明白题意,导致第一遍写的代码有些复杂和晦涩,这道题需要注意给的两个链表已经是相交的了,需要做的事去找到两者相交的那个点。

/**
 * 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* dummynodea = new ListNode(0);
        ListNode* dummynodeb = new ListNode(0);
        dummynodea -> next = headA;
        dummynodeb -> next = headB;
        ListNode* A = dummynodea;
        ListNode* B = dummynodeb;
        int counta = 0, countb = 0;
        while(A){
            A = A -> next;
            counta++;
        }
        while(B){
            B = B -> next;
            countb++;
        }
        A = dummynodea;
        B = dummynodeb;
        int s = counta-countb;
        if(counta > countb){
            while(s--){
                A = A -> next;
            }
            ListNode* tmp = A;
            while(A){
                if(A == B){
                    A = A -> next;
                    B = B -> next;
                }else{
                    return NULL;
                }
            }
            return tmp;
        } 

    }
};

这段代码并未完善,一是这道题无需使用虚拟头结点不必多此一举,其次判断A,B两链表谁长时不必再用if、else分情况讨论,只需要假定A长如果不是就将指针交换即可。

/**
 * 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* A = headA;
        ListNode* B = headB;
        int counta = 0, countb = 0;
        while(A){
            counta++;
            A = A -> next;
        }
        while(B){
            countb++;
            B = B -> next;
        }
        A = headA;
        B = headB;
        if(counta < countb){
            swap(counta,countb);
            swap(A,B);
        }
        int s = counta-countb;
        while(s--){
            A = A -> next;
        }
        while(A){
            if(A == B){
                return A;
            }
            A = A -> next;
            B = B -> next;
        }
        return NULL;
    }
};

这里提交的时候有遇到了一些问题,一个是间隔差s应该在交换两者指针之后的地方进行定义,改原先代码的时候没注意到这个点,再就是最后返回一个NULL,在无交点的情况下就需要返回一个NULL。

Leetcode - 142 环形链表

这道题还是重点在于解题思路代码的编写是一蹴而就的事情,这道题的思路实现判断是否为环,这里我们采用双指针的思想,用一快一慢两个指针一起出发,知道两者相遇即为存在环,这是进行下一步的思考,快指针走过的路是慢指针的两倍,我们假设入环前的路为x,入环后相遇的路为y,相遇后到入环点的路为z,这样我们就可以得出一个等式:(x+y)*2 = x+y+n(y+z),后者即快指针走过的路因为不知道是走了几圈才相遇的,这里我们化简得到x = (n-1)(y + z)+z即从head到入环点的距离为从相遇点到入环点的距离。

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

这里我还是有点疑问,最后化简的等式的最后不应该是n圈环的距离再加上z么?

这里的n圈是有多转了几圈后从相遇点开始向前走了z的距离到了入环点。

2024/2/26  20/14----magixx

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值