LeetCode刷题---链表

2024-10-09 16:08:37 浏览数 (1)

一、反转链表

1.分析

给定单链表头结点,反转链表之后返回新的头结点。 思路一:翻转指针

原本1号指针指向下一个节点2的,但是将1号指针翻转之后指向空,一直翻转直到5指向空翻转为5指向4. 所以我们就需要3个变量,一个节点存放指向其他节点的信息,另一个节点是被指向的节点,还需要一个节点来存放下一个节点的信息 思路2:头插法 将已知链表存放在一个新的链表中,将已知链表的每一个节点头插进新的链表中,需要三个变量:一个变量存放新的链表的节点信息,一个变量存放下一个节点的信息,一个变量来存放当前位置的信息

2.翻转指针

代码语言:javascript复制
struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL)
    {
        return NULL;
    }
    struct ListNode* n1 = NULL;//被指向的节点
    struct ListNode* n2 = head;//已知节点
    struct ListNode* n3 = n2->next;//存下一个节点的位置
    while (n2 != NULL)
    {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if (n3)
        {
            n3 = n3->next;
        }
    }
    return n1;
}

3.头插法

代码语言:javascript复制
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* cur = head;
    struct ListNode* newhead = NULL;
    while (cur)
    {
        struct ListNode* next = cur->next;
        cur->next = newhead;
        newhead = cur;
        cur = next;
    }
    return newhead;
}

二、链表的中间结点

1.分析

给定链表头结点,找出链表中间节点。 思路1:求长度,找中间值 定义一个变量len来表示长度,先遍历一遍链表,求出链表长度,然后直接就可以得出中间节点的位置 思路2:快慢指针 定义两个指针,一个slow一个fast,fast走两步,slow走一步,当fast到达最后一个节点或者fast出了链表之后,slow指针刚好到达中间节点,图示:

1.求长度,找中点

代码语言:javascript复制
struct ListNode* middleNode(struct ListNode* head) {
    int len = 0;
    struct ListNode* p1 = head;
    while (p1)
    {
        len  ;
        p1 = p1->next;
    }
    for (int i = 0;i < len / 2;i  )
    {
        head = head->next;
    }
    return head;
}

2.快慢指针

代码语言:javascript复制
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while (fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

三、合并两个有序链表

1.分析

思路1:尾插法 由上图可知可以创建一个新的链表,然后依次把两个链表中小的数尾插进新的链表,准备两个节点,一个节点遍历新的链表,一个节点始终指向新链表的头结点,用两个链表依次比较来填充新的链表 思路2:带哨兵位的头结点 利用带哨兵位的头结点,就排除了第一个指针为空的情况,就可以直接判断两个链表的val的大小。

2.尾插法

代码语言:javascript复制
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
    {
        return list2;
    }
    if (list2 == NULL)
    {
        return list1;
    }
    struct ListNode* head = NULL, * tail = NULL;
    while (list1 != NULL && list2 != NULL)
    {
        if (list1->val < list2->val)
        {
            if (tail == NULL)
            {
                head = tail = list1;
            }
            else
            {
                tail->next = list1;
                tail = tail->next;
            }
            list1 = list1->next;
        }
        else
        {
            if (tail == NULL)
            {
                head = tail = list2;
            }
            else
            {
                tail->next = list2;
                tail = tail->next;
            }
            list2 = list2->next;
        }
    }
    if (list1 != NULL)
    {
        tail->next = list1;
    }
    if (list2 != NULL)
    {
        tail->next = list2;
    }
    return head;
}

注:可以提前准备头结点,省去两个判断是否为空的if语句 算法优化:

代码语言:javascript复制
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
    {
        return list2;
    }
    if (list2 == NULL)
    {
        return list1;
    }
    struct ListNode* head = NULL, * tail = NULL;
    if (list1->val < list2->val)
    {
        head = tail = list1;
        list1 = list1->next;
    }
    else
    {
        head = tail = list2;
        list2 = list2->next;
    }
    while (list1 != NULL && list2 != NULL)
    {
        if (list1->val < list2->val)
        {
            tail->next = list1;
            tail = tail->next;
            list1 = list1->next;
        }
        else
        {
            tail->next = list2;
            tail = tail->next;
            list2 = list2->next;
        }
    }
    if (list1 != NULL)
    {
        tail->next = list1;
    }
    if (list2 != NULL)
    {
        tail->next = list2;
    }
    return head;
}

3.带哨兵位的头节点

代码语言:javascript复制
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
    {
        return list2;
    }
    if (list2 == NULL)
    {
        return list1;
    }
    struct ListNode* head = NULL, * tail = NULL;
    head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
    while (list1 != NULL && list2 != NULL)
    {
        if (list1->val < list2->val)
        {
            tail->next = list1;
            tail = tail->next;
            list1 = list1->next;
        }
        else
        {
            tail->next = list2;
            tail = tail->next;
            list2 = list2->next;
        }
    }
    if (list1 != NULL)
    {
        tail->next = list1;
    }
    if (list2 != NULL)
    {
        tail->next = list2;
    }
    return head->next;
}

四、环形链表

1.分析

思路:通过快慢指针,创建两个指针,一个fast指针,一个slow指针,slow指针一次走一步,fast指针一次走两步,因为fast指针走的快,所有有两种情况。 第一种情况:

第二种情况:

第二种情况就是环形链表,因为fast走的快所以fast先进入环形区域,所以fast在环形区域中已知旋转,当slow进入环形区域中时solw和fast最终会相遇,所以结束标志就是fast==slow如果是非环形链表的话直接就出循环了。

2.快慢指针

代码语言:javascript复制
bool hasCycle(struct ListNode* head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if (slow == fast)
        {
            return true;
        }
    }
    return false;
}

0 人点赞