链表经典算法(2)

本文介绍了如何使用快慢指针解决链表中倒数第k个节点的问题,以及如何在O(n)时间内判断链表是否为回文结构和找到两个链表的第一个公共结点。通过实例和代码展示了这些经典链表问题的解法。
摘要由CSDN通过智能技术生成

前言:基于对链表初步理解及经典算法题(1)(具体内容参考往期博客),我们继续完成几道链表经典算法题

1,输入一个链表,输出该链表中倒数第k个结点

面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

注意:本题相对原题稍作改动

示例:

输入: 1->2->3->4->5 和 k = 2
输出: 4

说明:

给定的 k 保证是有效的。

思路

快慢指针 快必慢多走k步

参考代码

int kthToLast(struct ListNode* head, int k)
{
    struct ListNode* fast = head, *slow = head;
    //快指针先走k步
    while(k--)
    {
        fast = fast->next;
    }
    //同时走
    while(fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow->val;
}

2,链表的回文结构 

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

描述

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:

1->2->2->1
返回:true

思路

先找到中间节点

再将中间节点往后反转链表

最后将头结点与中间节点依次比较,若值相同则依次比较下一个节点的值

参考代码 

#include <algorithm>
class PalindromeList {
public:
    struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* slow = head;
    struct ListNode* fast = head; 
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}
    struct ListNode* reverseList(struct ListNode* head)
 {
    if(head == NULL)
    {
        return head;
    }
    struct ListNode* n1,*n2,*n3;
    n1 = NULL,n2 = head,n3 = n2->next;
    while(n2)
    {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if(n3)
        {
            n3 = n3->next;
        }
    }
    return n1;
}
    bool chkPalindrome(ListNode* A) 
    {
        // write code here
        struct ListNode* mid = middleNode(A);
        struct ListNode* rmid = reverseList(mid);
        while(rmid && A)
        {
            if(rmid->val != A->val)
            {
                return false;
            }
            rmid = rmid->next;
            A = A->next;
        }
        return true;
    }
};

注:找中间节点及反转链表相关函数参照《单链表经典算法-CSDN博客》 

3,输入两个链表,找出它们的第一个公共结点

160. 相交链表 - 力扣(LeetCode)

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。

思路

1,判断是否相交

判断尾指针,注意要用地址判断

2,若相交,找出第一个交点

思路一

A链表的节点依次跟B链表所有节点比较,A某个节点跟B链表某个节点相等,则这个节点即为交点

时间复杂度O(N^2)

思路二

大链表节点数减去小链表节点数 即为多出部分 依次可以借助减数一个一个比较

时间复杂度O(N) 

参考代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode * curA = headA,*curB = headB;
    int lenA = 1, lenB = 1;
    while(curA->next)
    {
        curA = curA->next;
        ++lenA;
    }
    while(curB->next)
    {
        curB = curB->next;
        ++lenB;
    }
    //尾结点不相等就不相交
    if(curA != curB)
    {
        return NULL;
    }
    //长的先走差距步,再同时走,第一个相交的就是交点
    //假设法
    int gap = abs(lenA - lenB);
    struct ListNode* longList = headA,*shortList = headB;
    if(lenB > lenA)
    {
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
        longList = longList->next;
    }
    while(longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;
    }
    return longList;
    
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表排序可以使用多种算法实现,下面是一种基于插入排序的链表排序算法的C语言实现: ```c #include <stdio.h> #include <stdlib.h> /* 定义链表节点结构体 */ typedef struct ListNode { int val; struct ListNode *next; } ListNode; /* 插入排序算法实现 */ ListNode* insertionSortList(ListNode* head) { if (!head || !head->next) return head; // 链表为空或只有一个节点,直接返回 ListNode *dummy = (ListNode *)malloc(sizeof(ListNode)); // 创建哑节点 dummy->next = head; ListNode *p = head->next, *q = head; // p指向要插入的节点,q指向p的前一个节点 while (p) { ListNode *r = dummy; // r指向已排序部分的哑节点 while (r != q && r->next->val <= p->val) r = r->next; // 在已排序部分中找到插入位置 if (r != q) { q->next = p->next; p->next = r->next; r->next = p; p = q->next; } else { p = p->next; q = q->next; } } head = dummy->next; free(dummy); // 释放哑节点 return head; } /* 创建链表 */ ListNode* createList(int arr[], int n) { if (n == 0) return NULL; ListNode *head = (ListNode *)malloc(sizeof(ListNode)); head->val = arr[0]; head->next = NULL; ListNode *p = head; for (int i = 1; i < n; i++) { ListNode *q = (ListNode *)malloc(sizeof(ListNode)); q->val = arr[i]; q->next = NULL; p->next = q; p = p->next; } return head; } /* 打印链表 */ void printList(ListNode *head) { while (head) { printf("%d ", head->val); head = head->next; } printf("\n"); } int main() { int arr[] = {3, 1, 4, 2, 5}; int n = sizeof(arr) / sizeof(int); ListNode *head = createList(arr, n); printf("原链表:"); printList(head); head = insertionSortList(head); printf("排序后:"); printList(head); return 0; } ``` 该程序中,insertionSortList函数实现了链表的插入排序算法,createList函数用来创建链表,printList函数用来打印链表。在main函数中,先创建一个链表,然后打印原链表,对链表进行排序,最后再打印排序后的链表

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值