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

29 篇文章 0 订阅
3 篇文章 0 订阅

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

力扣题目链接(opens new window)

解析:

基础题,主要是要把握边界条件:由题可得,交换的节点两两一组,每交换完成一对,问题规模减2,也就是只剩一个或不剩节点时交换便结束

在这里,我们引入一个虚拟头节点,这样所有的交换操作便得到统一。

每一对节点交换一次,不开辟额外空间,因此时间复杂度O(n),空间复杂度O(1)

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy_head = new ListNode(-1, head); //虚拟头节点
        if(head == nullptr || head->next == nullptr) return head; //边界条件先判断
        ListNode* cur2 = head->next;
        ListNode* cur1 = head;
        ListNode* pre = dummy_head; //两个需要交换的节点,及前节点,共三个节点
        while(cur1 && cur2){
            cur1->next = cur2->next;
            cur2->next = cur1;
            pre->next = cur2;

            pre = cur1;
            if(cur1->next && cur1->next->next){ //若只剩1个或不剩 则退出交换
                cur2 = cur1->next->next;
                cur1 = cur1->next;
            }
            else {
                break;
            }
        }
        head = dummy_head->next; //头节点还原
        delete dummy_head;
        return head;
    }
};

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

力扣题目链接

解析:

本题以普通办法处理的话就是先遍历一遍,确定链表长度,再遍历一遍,实施删除。虽然不会到O(n^2)的复杂度,仍为线性,但是连续遍历两遍不免让人觉得不快。

因此此类问题,同样可以借鉴双指针法,一前一后不回溯的遍历链表,让前后指针距离保持 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* dummy_head = new ListNode(-1,head);
            ListNode* p = dummy_head;
            ListNode* q = dummy_head;
            int kick_off = 0;
            while(kick_off < n && p->next){ //先让p指针先行,确定q指针何时行动
                p = p->next;
                kick_off++;
            }
            while(p->next){ //同步行动,直至p指针到最后一个节点,q指针离p n 个位置远
                p = p->next;
                q = q->next;
            }
            ListNode *tmp = q->next;
            q->next = q->next->next; //实施删除

            if(dummy_head->next){ //判断一下是否链表就一个节点,且已被删除
                head = dummy_head->next;
            }
            else{
                head = nullptr;
            }
            delete tmp; // 回收要删除的节点
            delete dummy_head; //回收虚拟头
            return head;
    }
};

160.链表相交

力扣题目链接(opens new window)

解析:

这道题需要巧妙利用到一个思维,也就是链表尾对齐的思维。

如图:若两个链表有相交点,则该交点后的节点均为同一个节点,也就是它们是尾部相等的。所以如果我们能找到长表较之于短表表头的中间位置(等长的位置),然后顺序同步一对一对节点的比较是否相等,便能找到第一个相同的节点,且时间复杂度能控制在O(m+n)。

/**
 * 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* qq = headA;
        int lenA = 1;
        int lenB = 1;
        ListNode* pp = headB;
        while(qq->next){ //计算A的长度
            qq = qq->next;
            lenA++;
        }
        while(pp->next){ //计算B的长度
            pp = pp->next;
            lenB++;
        }
        ListNode* q = headA;
        ListNode* p = headB;
        if(lenA < lenB){ // 让q指向较长的链表的表头
            int tmp = lenA;
            ListNode* _tmp = q; 
            lenA = lenB;
            lenB = tmp;
            q = p;
            p = _tmp;
        }
        int offset = lenA - lenB;
        while(offset > 0 ){ //想象两个不等长的链表,由末尾对齐,将较长的链表的指针遍历到与较短的链表表头节点对齐
            q = q->next;
            offset--;
        }
        while(q != p && q){ //开始判等
            q = q->next;
            p = p->next;
        }
        return q;
    }
};

142.环形链表II

力扣题目链接

解析:

该题涉及到一个数学推理,详情见卡哥:代码随想录

/**
 * 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* p = head;
        ListNode* q = head;
        while( q && q->next){
            p = p->next;
            q = q->next->next;
            if(p == q){
                ListNode* pp = head;
                ListNode* qq = q;
                while(pp != qq){
                    pp = pp->next;
                    qq = qq->next;
                }
                return qq;
            }
        }
        return NULL;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值