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

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

即第一个第二个换,第三个第四个换……
自己先思考了一个,while之前是对的(笑死)。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* left;
        ListNode* right;
        ListNode* tmp;
        ListNode* dummyHead = new ListNode();
        dummyHead->next = head;
        left = dummyHead;
        if (left->next == nullptr || left->next->next == nullptr) {
            ;
        } else if (left->next->next->next == nullptr) {
            right = left->next->next;
            tmp = left->next;
            left->next = right;
            left = left->next;
            right->next = tmp;
            left->next = nullptr;

        } else {
            while (left->next->next->next != nullptr) {
                right = left->next->next;
                tmp = left->next;
                left->next = right;
                left = right;
                right->next = tmp;
            }
        }
        return dummyHead->next;
    }
};

看完解释之后自己又写了一下:

/**
 * 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* left;
        ListNode* right;
        ListNode* tmp;
        ListNode* tmp1;
        ListNode* dummyHead = new ListNode();
        dummyHead->next = head;
        left = dummyHead;
        if (left->next != nullptr)//上下范围我还是没界定好,这个要再想想。
            ;
        while (left->next != nullptr &&
               left->next->next != nullptr) {
            right = left->next->next;
            tmp = left->next;
            tmp1 = right->next;
            left->next = right;
            right->next = tmp;
            tmp->next = tmp1;
            left = tmp;
        }

        return dummyHead->next;
    }
};

while (left->next != nullptr && left->next->next != nullptr)再想一下这个范围,left换完之后始终在最左边,右边要参与交换的顶多2个节点,因此最多2个next

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

写的很顺,其实也不太顺,运行结果有几次不通过,看着结果又想了一遍,通过了运行,但没通过提交。
我的想法是:
倒数第几个,用双指针思想的话,就是当快指针到达NULL的时候,和慢指针相差n个
慢指针指向当前需要被删除的,如果当前节点之前还有节点的话,或者当前节点之后的节点个数是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* dummyHead = new ListNode();
        dummyHead->next = head;
        ListNode* fast = dummyHead;
        ListNode* cur = fast;
        ListNode* slow = new ListNode();
        int k = 0;
        while (n--)
            fast = fast->next;
        while (fast != nullptr) {
            slow = cur;
            cur = cur->next;
            fast = fast->next;
            k++;//计算当前节点之前有多少个节点
        }
        if (k == 1)
            dummyHead->next = nullptr;
        if (k > 1) {
            if (cur->next != nullptr)
                slow->next = cur->next;
            else {
                slow->next = nullptr;
            }
        }
        return dummyHead->next;
    }
};

下面是卡哥的代码,真简洁干净啊

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        n++; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
        while(n-- && fast != NULL) {
            fast = fast->next;
        }
        while (fast != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next; 
        
        // ListNode *tmp = slow->next;  C++释放内存的逻辑
        // slow->next = tmp->next;
        // delete tmp;
        
        return dummyHead->next;
    }
};

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) {
        int intersectVal = 0, skipA = 0, skipB = 0;
        ListNode* curA = headA;
        ListNode* curB = headB;
        while (curA != NULL && curB != NULL) {
            if(curA == curB)
            {
                intersectVal = curA->val;
                break;
                }
            curA = curA->next;
            skipA++;
            curB = curB->next;
            skipB++;
        }
        if(intersectVal==0)
        cout<<"null";
        else
        {
            cout<<"intersected at '"<<intersectVal<<"'";
        }
    }
    return ;
};

卡子哥比我想得更全:
1.遍历2个链表求长度,后续让两个链表对齐
2.起点不同,对齐之后让curA(长的链)移动到,和curB (短的链)末尾对齐的位置
/我也是想了一下这是为什么,很简单,题目里给出的所有案例都是对其的,我没有关注到这点,所以定位完全错误/

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while (curA != NULL) { // 求链表A的长度
            lenA++;
            curA = curA->next;
        }
        while (curB != NULL) { // 求链表B的长度
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            swap (lenA, lenB);
            swap (curA, curB);
        }
        // 求长度差
        int gap = lenA - lenB;
        // 让curA和curB在同一起点上(末尾位置对齐)
        while (gap--) {
            curA = curA->next;
        }
        // 遍历curA 和 curB,遇到相同则直接返回
        while (curA != NULL) {
            if (curA == curB) {
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return NULL;
    }
};

142.环形链表II

写两个while嵌套的时候我就知道会超时QAQ。时空复杂度我还是有些拿捏不住

/**
 * 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*cur = head;
        ListNode*cir = head;
        int pos = -1;
        while(cir != NULL){
           pos = -1;
            while(cur != NULL)
          { cur = cur->next;
              if(cur->next == cir)
            {
                break;
            } 
          }
          cir = cir->next;
          pos++;
        }
        return cir;
    }
};

速度记下!!
仍旧是快慢指针,追及问题,快指针以每次2个单位的速度移动,慢指针是1个,他们最终一定在环里相遇(如果有)。因为进入环之后,快指针用相对于慢指针1个单位速度追它,因此是一定会追上的,不会跳过!!-相对位置始终在缩小1-
在这里插入图片描述
这个等式也有意思,慢指针一定只走了一圈就会被追上,为什么呢?
因为在慢指针走满一圈的时候,快指针已经走了2圈,他们的相对距离又总是在一个单位一个单位的缩小。所以在相遇的时候慢指针必定没走够一圈,而快指针必然已经绕了一圈。
在这里插入图片描述

看完快慢指针和追及问题后写的代码,但是还是超出限制时间,笑得,又是没加跳出循环的break,加完之后提交成功了。第一个while里一定要有break!!还有就是定义指针的时候,让他们有所指。

/**
 * 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=head;
        ListNode *index2 = head;
        int pos = -1;
        while (fast != NULL && slow != NULL) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) {
                index1 = fast;
                pos = 0;
                break;
            }
        }
        while (index1 != index2) {
            index1 = index1->next;
            index2 = index2->next;
            pos++;
        }
        if(pos == -1)
        return NULL;
        else
        return index1;
    }
};

在这里插入图片描述
卡子哥的循环嵌套更有意思点,看似双层嵌套,但是在追上的那一刻快慢指针就静止了,换成了相遇点和起点的指针出发。所以更快

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;
            // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
            if (slow == fast) {
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2; // 返回环的入口
            }
        }
        return NULL;
    }
};

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值