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

前言

思路及算法思维,指路 代码随想录
题目来自 LeetCode

day 4,一个工作日的周六,坚持一下也不是很困难~

题目详情

[24] 两两交换链表中的节点

题目描述

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

解题思路

前提:单链表 + 交换链表节点(不是节点数值)
思路:节点两两一组,改变涉及的3个node的next指针指向即可。
重点:考虑是否使用虚拟头结点,如果不适用虚拟头结点,需要单独处理头节点一组的情况,所以建议使用虚拟头节点,所有节点统一处理。

代码实现

C语言
虚拟头节点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* swapPairs(struct ListNode* head) {
    struct ListNode *vHead = (struct ListNode *)malloc(sizeof(struct ListNode));
    vHead->next = head;
    struct ListNode *cur = vHead;
    while (cur->next && cur->next->next)
    {
        struct ListNode *pre = cur;
        struct ListNode *tmp = cur->next->next;
        cur->next->next = tmp->next;
        tmp->next = cur->next;
        pre->next = tmp;
        cur = cur->next->next;
    }
    head = vHead->next;
    free(vHead);
    return head;
}

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

题目描述

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

解题思路

前提:单链表 + 删除倒数第n个结点
思路:双指针方法,两个指针间隔n个结点,当快指针到链表表尾时,慢指针指向的节点就是需要删除的节点。(暴力解法:遍历链表节点长度,再遍历到节点位置,时间复杂度高~)
重点:删除结点时,需要使用该结点的前置结点。

代码实现

C语言
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
    struct ListNode *vHead = (struct ListNode *)malloc(sizeof(struct ListNode));
    vHead->next = head;
    struct ListNode *fast = vHead;
    struct ListNode *slow = vHead;
    while (n--)
    {
        fast = fast->next;
    }
    struct ListNode *tmp = NULL;
    while (fast)
    {
        fast = fast->next;
        tmp = slow;
        slow = slow->next;
    }
    tmp->next = slow->next;
    free(slow);
    head = vHead->next;
    free(vHead);
    return head;
}

[面试题02.07] 链表相交

题目描述

面试题02.07 链表相交
面试题02.07 链表相交

解题思路

前提:链表相交
思路:链表相交,是指同一个结点,而不是结点数值一致;并且,当链表相交之后,相交点之后的结点均是同一个结点。
重点:链表若相交,从相交点后,结点的长度、地址均一致。

代码实现

C语言

计算两个链表的长度,找到公共长度部分,开始比较结点地址是否一致。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int listSizeA = 0;
    int listSizeB = 0;
    int size = 0;
    struct ListNode *curA = headA;
    struct ListNode *curB = headB;
    while (curA)
    {
        listSizeA++;
        curA = curA->next;
    }
    while (curB)
    {
        listSizeB++;
        curB = curB->next;
    }
    curA = headA;
    curB = headB;
    if (listSizeA > listSizeB)
    {
        size = listSizeB;
        int offset = listSizeA - listSizeB;
        while ((curA) && (offset--))
        {
            curA = curA->next;
        }
        curB = headB;
    }
    else
    {
        size = listSizeA;
        int offset = listSizeB - listSizeA;
        while ((curB) && (offset--))
        {
            curB = curB->next;
        }
        curA = headA;
    }
    while (curA && curB)
    {
        if (curA == curB)
        {
            break;
        }
        curA = curA->next;
        curB = curB->next;
    }
    return curA;
}

[142] 环形链表II

题目描述

142 环形链表II
142 环形链表II

解题思路

前提:单链表 + 表中可能有环
思路:双指针,快指针每次走两步,慢指针每次走一步,如果存在环,当快指针和慢指针均在环中时,总会相遇,此时快指针比慢指针多执行nC步(C为环长度,n=1, 2, 3……),当n = 1时,慢指针环外的长度 = 快指针环内该圈未经过的长度,所以快指针调整为一步一步前行,慢指针从链表头一步一步前行,相遇的点就是链表入环的结点;当n > 1时,无非就是快指针在环内多循环几圈,相遇点依旧是链表入环的结点。
重点:双指针判断链表是否有环的思路,以及,如果确定链表入环的结点。

代码实现

双指针
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    bool found = false;
    if (head == NULL || head->next == NULL ||head->next->next == NULL)
    {
        return NULL;
    }
    slow = head->next;
    fast = head->next->next;
    while (slow && fast)
    {
        if (slow == fast)
        {
            found = true;
            break;
        }
        if (!slow->next || !fast->next || !fast->next->next)
        {
            break;
        }
        slow = slow->next;
        fast = fast->next->next;
    }
    if (!found)
    {
        return NULL;
    }
    slow = head;
    while (slow && fast)
    {
        if (slow == fast)
        {
            break;
        }
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

今日收获

  1. 链表的使用。
  2. 链表相交,就是同一结点。
  3. 链表有环的判断方法,以及判断链表入环的结点。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值