顺序表链表OJ题(2)->【数据结构】

简介: 顺序表链表OJ题(2)->【数据结构】

前言:


单链表的结构常常不完美,没有双向链表那么”优秀“,所以繁衍出很多OJ练习题。今天我们继续来look look数据结构习题。


下面就是OJ时间!!!


【链表中倒数第K个节点】——牛客网

OJ链接


描述

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


示例1

输入:

1,{1,2,3,4,5}

返回值:

{5}

题目函数接口:

8ee5336119b74b0abb68ed5eb18877d5.png

pListHead:目标链表。k:倒数第K个节点。


理论上我们可以先遍历一遍求出链表长度,然后创建一个指针使其走过(k-1)个元素即可找到链表中倒是第k个节点。


但是这道题我们要把时间复杂度降到最大,只能遍历一遍,我们该怎么应对?


我们可以创建两个指针(快慢)slow和fast,将fast先走k个节点,然后让fast与slow开始一块走,直到fast指向NULL停止,这时slow指向的节点就是我们需要倒数第k个节点!!!

978d1a4758214628ac87c41faa3c73ab.png

这里的快慢指针所使用的是路程差,让fast先走k个就是让slow少走k个,所得到的节点就是倒数第k个节点。

代码演示:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* slow = pListHead;
    struct ListNode* fast = pListHead;
    while(k--)
    {
        if(fast == NULL)
            return NULL;
        fast = fast->next;
    }
    while(fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

【leetcode 21.合并两个有序链表】

OJ链接

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

589a3c0407264c18b2624fda49f9c86c.png

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1l2 均按 非递减顺序 排列


题目函数接口:

31dbb9e08f3d4c9fb73857bdc34a3e4a.png

list1:目标链表1。list2:目标链表2。


这道题与上篇博客中合并顺序表思路大同小异,创建一个新节点,取小的尾插到节点后面即可。

我们可以创建两个指针head与tail,head记录新链表的头节点,tail记录新链表的尾节点。

3ae1ffb921a744be90c81c3ca936c9ee.png

代码演示:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* cur = list1;
    struct ListNode* tal = list2;
    struct ListNode* head = NULL;
    struct ListNode* tail = NULL;
    if(list1 == NULL)
        return list2;
    if(list2 == NULL)
        return list1;
    while(tal && cur)
    {
        if(cur->val>=tal->val)
        {
            if(head == NULL)
            {
                head = tail = list2;
            }
            else
            {
                tail->next = tal;
                tail = tail->next;
            }
            tal = tal->next;
        }
        else
        {
            if(cur->val<tal->val)
            {
                if(head == NULL)
                {
                    head = tail = list1;
                }
                else
                {
                    tail->next = cur;
                    tail = tail->next;
                }
            }
            cur = cur->next;
        }
    }
    if(cur)
        tail->next = cur;
    if(tal)
        tail->next = tal;
    return head;
}

注意:这种题我们就必须考虑完善,比如:一个链表为空,我们就应该考虑这种情况应该直接返回另一个链表即可。

if(list1 == NULL)
        return list2;
if(list2 == NULL)
        return list1;

这四句就是考虑为空的情况的,所以我们做题必须全面!!!


【CM11  链表分割】——牛客网

OJ链接


描述:

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

题目函数接口:

c1ad145b0d8942fb8dec8109bf1a3116.png

我们一看这个函数接口为c++,但是c++与c在这个函数中内容相同,所以使用c语言也是ok


pHead:目标链表。x:分割数。


我们先举个实际例子说清楚题目含义:【1 3 2 5 1】x = 3


我们就应该以3为分界线,将小于3的放在链表前面,大于等于3的放在链表后面且顺序不能改变,得到的顺序应该为:【1 2 1 3 5】。


那我们该如何实现呢?


我们可以创建两条链表,将小于x的放入链表1,大于等于x的放入链表2中,然后进行合并即可得到结果。

b2170c29c8a6416eb73f259386f76bb0.png

大致思路已经出炉,现在我们应该考虑一下细节该怎么处理。


两条链表我们应该选带哨兵位的还是不带哨兵位的?


哨兵位是为了我们更好的头插,一般情况下带不带哨兵位都可以,不使用哨兵位可以使用二级指针进行操作,效果是相同的。但是这道题是带哨兵位的链表简单些,因为有特殊情况,比如小于x的链表内容为空,如果我们我们进行合并,可能会丢失数据,所以我们得用很多if语句进行判断才行,但是有了哨兵位就不需要考虑这么多问题。


代码演示:

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        ListNode*ghead = NULL;
        ListNode*gtail = NULL;
        ListNode*lhead = NULL;
        ListNode*ltail = NULL;
        ghead = gtail = (ListNode*)malloc(sizeof(ListNode));
        lhead = ltail = (ListNode*)malloc(sizeof(ListNode));
        ListNode*cur = pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                ltail->next = cur;
                ltail = ltail->next;
            }
            else
            {
                gtail->next = cur;
                gtail = gtail->next;
            }
            cur = cur->next;
        }
        ltail->next = ghead->next;
        gtail->next = NULL;
        ListNode*head = lhead->next;
        free(lhead);
        free(ghead);
        return head;
    }
};

【OR36 链表的回文结构】——牛客网

OJ链接


描述:


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


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


测试样例:


1->2->2->1


返回:true


题目函数接口:

dad109c19334428bac315dc0a907311b.png

A:目标链表。


那什么是回文呢?


奇数回文:1->2->3->2->1  偶数回文:1->2->2->1


如果是数组,可以从后往前进行非常简单,但是这时链表,应该怎么办呢?


使用快慢指针找到链表的中间节点,将中间节点后面的链表内容反转,然后用两个指针,一个在中间节点处,一个在链表最开始出,进行移动比较,如果都相同则为回文结构,反之则不是回文结构。

7dbd65db5d1b432189226949bfcbc74c.png

代码演示:

class PalindromeList {
public:
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;
}
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;
}
    bool chkPalindrome(ListNode* A) {
        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;
    }
};


此程序我们封装了两个函数,一个为寻找中间节点的函数,一个为链表反转函数。当我们反转链表后,我们不需要将中间节点的next重新连接,让其成为相交链表即可。

这样判断的长度也一样,不需要考虑何时停止。


【leetcode 160.相交链表】

OJ链接


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

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

821927b31330388dc751c94d91222db9.png

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

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

自定义评测:

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


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


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

3d9a3c0647de446c814c00371cf4368b.png

题目函数接口:

e24261fa8a324d958dcf278c8ffb08a5.png

headA:目标链表A。headB:目标链表B。


如何判断两个链表相交,因为单链表一个结构体中只有一个next节点存放下一个结构体,所以只需要判断尾节点地址是否相等即可。虽然我们找的不是最开始相交的点,但是这样的思想非常简便。


首先按照前面思路,判断两个链表是否相交,如果不相交就没有做下去的必要了,直接返回NULL即可。但是如果有节点我们就要寻找起始节点位置。


两个相交链表是由一段不相交的与一段相交的组合一起的,两段链表不一样长的那一段一定在不相交的位置。所以我们可以让较长的链表先遍历两个链表长度之差个节点,这样两个链表就一样长了,再进行逐一比较即可找到起始相交节点!!!

704f10ae56ac43fc940e9e131b58598d.png那我们想要知道两个链表长度就可以再判断两个链表是否相交时进行计数,因为判断两个链表相交就是判断尾节点是否相等,就是要将两个链表全部遍历一遍,一举两得。


理论形成,实践开始:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int lena = 1;
    int lenb = 1;
    struct ListNode *cura = headA;
    struct ListNode *curb = headB;
    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 *llist = headA;
    struct ListNode *slist = headB;
    if(lena > lenb)
    {
       ;
    }
    else
    {
        llist = headB;
        slist = headA;
    }
    while(gap--)
    {
        llist = llist->next;
    }
    while(llist != slist)
    {
         llist = llist->next;
         slist = slist->next;
    }
    return llist;
}

【leetcode 141.环形链表】

OJ链接


给你一个链表的头节点 head ,判断链表中是否有环。


如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。


如果链表中存在环 ,则返回 true 。 否则,返回 false 。

be80748bf8fb430c81e1376be61aa32e.png题目函数接口:

c878b138c7f04568a6e98ce57d4a1fc0.png

head:目标链表。


什么是环形链表,我们最先见到过的就是循环列表:

e2842cd43c4b4cceb0327e35bf86a363.png

但其实环形链表还有很多:

b94da32e23f44d9eb340cfec66fa3916.png向上面的我们都可以称作环形链表。


那我们应该怎样判断出链表为环形链表呢?


这里我们还是基于快慢指针进行,如同数学中的追及问题一样,如果在一个环形跑到中,两个人速度不同,但是快的人落后于慢的人,快的人总会追到慢的人。


我们创建两个指针fast与slow,s两个人都从开始进行,slow走一步,fast走两步,如果有环它们一定会进入环中进行追及。

e3b97c50df664f1ebeef536342025d20.png代码演示:

bool hasCycle(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    while(fast && fast->next)
    {
         fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            return true;
        }
    }
    return false;
}

以上是本次数据结构OJ题分享,感谢大家观看,三连支持一下博主,博主会干劲十足的!!!

目录
相关文章
|
12月前
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
213 4
|
9月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
318 30
|
9月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
415 25
|
9月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
10月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
465 5
|
10月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
本文档介绍了线性表的基本运算任务,涵盖顺序表和链表的初始化、销毁、判定是否为空、求长度、输出、查找元素、插入和删除元素等内容。通过C++代码示例详细展示了每一步骤的具体实现方法,并提供了测试说明和通关代码。 主要内容包括: - **任务描述**:实现顺序表的基本运算。 - **相关知识**:介绍线性表的基本概念及操作,如初始化、销毁、判定是否为空表等。 - **具体操作**:详述顺序表和链表的初始化、求长度、输出、查找、插入和删除元素的方法,并附有代码示例。 - **测试说明**:提供测试输入和预期输出,确保代码正确性。 - **通关代码**:给出完整的C++代码实现,帮助完成任务。 文档
297 5
|
11月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
存储
顺序表和链表(2)
【10月更文挑战第23天】
208 2
顺序表和链表(2)
|
12月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
348 5
|
12月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
291 0

热门文章

最新文章