经典单链表OJ题

news2024/11/19 0:22:41

目录

1、轮转数组

2、返回倒数第k个节点

3、判断链表的回文结构

4、两个链表,找出它们的第一个公共结点

5、随机链表的复制

6、判断链表中是否有环

7、返回链表开始入环的第一个节点


1、轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3

输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

思路:

先逆置后k个元素

再逆置前n-k个元素

最后整体逆置

void Reverse(int* nums,int a,int b)
{
    int k = (b-a+1)/2;
    while(k--)
    {
        int tmp = nums[a];
        nums[a] = nums[b];
        nums[b] = tmp;
        ++a;
        --b;
    }
}

void rotate(int* nums, int numsSize, int k)
{
    k = k % numsSize;//逆置numSize次不变
    Reverse(nums,numsSize-k,numsSize-1);
    Reverse(nums,0,numsSize-k-1);
    Reverse(nums,0,numsSize-1);
}

2、返回倒数第k个节点

找出单向链表中倒数第 k 个节点,返回该节点的值

示例:

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

说明:

给定的 k 保证是有效的

思路1:

先遍历链表,算出节点个数count

再遍历count-k次,找到倒数第k个节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


int kthToLast(struct ListNode* head, int k)
{
    struct ListNode* cur = head;
    int count = 0;
    while(cur)
    {
        count++;
        cur = cur->next;
    }

    cur = head;
    int n = count-k;
    while(n--)
    {
        cur = cur->next;
    }

    return cur->val;
}

思路2:

快慢指针 fast slow

fast指针先走k步

fast和slow一起走

直到fast为NULL,slow指向倒数第k个节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


int kthToLast(struct ListNode* head, int k)
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while(k--)
    {
        fast = fast->next;
    }
    while(fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow->val;
}

3、判断链表的回文结构

描述:

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

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

测试样例:

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

思路:

找中间节点,偶数后一个

逆置后半部分的链表

判断相等

//找中间节点
struct ListNode* MiddleNode(struct ListNode* head) {
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    //注意两种情况用whlie(&&),我看了几小时,已废
    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

//逆置链表
struct ListNode* ReverseList(struct ListNode* head) {
    struct ListNode* cur = head;
    if (cur == NULL) {
        return head;
    }
    struct ListNode* next = head->next;
    if (next == NULL) {
        return head;
    }
    while (next) {
        struct ListNode* tail = next->next;
        next->next = cur;
        cur = next;
        next = tail;
    }
    head->next = NULL;
    return cur;
}

bool test(ListNode* head)
{
    struct ListNode* mid = MiddleNode(head);
    struct ListNode* head1 = ReverseList(mid);
    while (head1 != NULL) {
        if (head->val != head1->val)
            return false;
        else {
            head = head->next;
            head1 = head1->next;
        }
    }
    return true;
}

4、两个链表,找出它们的第一个公共结点

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

整个链式结构中不存在环

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

思路1:

 双重嵌套遍历

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    while(headA)
    {
        struct ListNode* s = headB;
        while(s)
        {

            if(headA == s)
            {
                return headA;
            }
            else
            {
                s = s->next;
            }
        }
        headA = headA->next;
    }
    return NULL;
}

思路二:

先遍历连个链表,k为节点差值

LongList先走k步

再LongList和ShortList一起走

若LongList == ShortList,即为共同节点,否则返回NULL

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* getIntersectionNode(struct ListNode* headA,struct ListNode* headB)
{
    struct ListNode* A = headA;
    struct ListNode* B = headB;
    int countA = 0;
    int countB = 0;
    while (A)
    {
        countA++;
        A = A->next;
    }
    while (B)
    {
        countB++;
        B = B->next;
    }

    struct ListNode* LongList = headA, *ShortList = headB;
    if(countA<countB)
    {
        LongList = headB;
        ShortList = headA;
    }

    int k = abs(countA - countB);
    while(k--)
    {
        LongList = LongList->next;
    }
    while(LongList)
    {
        if(LongList == ShortList)
        {
            return LongList;
        }
        else
        {
            LongList = LongList->next;
            ShortList = ShortList->next;
        }
    }
    return NULL;
}

5、随机链表的复制

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点

要求返回这个链表的深度拷贝

即建立一个新链表与原链表一模一样,且复制链表中的指针都不应指向原链表中的节点 

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

注意:[13,0],0表示指向下标为0的节点

思路:

原链表:A --> B --> C --> D

先复制值 A --> A' --> B --> B' --> C --> C' --> D --> D'

再复制random(以A'举例) A->next->random = A->random->next;(A->random = NULL,另做讨论)

最后连接复制链表 A' --> B' --> C' --> D'

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) {
    struct Node* cur = head;
    if(cur == NULL)
    {
        return cur;
    }
	else
    {
    
    //复制值 
    while(cur)
    {
        struct Node* Node = (struct Node*)malloc(sizeof(struct Node));
        Node->val = cur->val;
        Node->next = cur->next;
        cur->next = Node;
        cur = cur->next->next;
    }

    //复制random
    cur = head;
    while(cur)
    {
        if(cur->random == NULL)
        {
            cur->next->random = NULL;
        }
        else
        {
            cur->next->random = cur->random->next;
        }
        cur = cur->next->next;
    }

    //连接复制链表
    cur = head;
    struct Node* copyhead = head->next;
    struct Node* copytail = head->next;
    while(cur)
    {
        struct Node* next = copytail->next;//先保留原链表节点
        if(next == NULL)
        {
            cur->next = next;//还原原链表
            cur = next;
        }
        else
        {
            copytail->next = copytail->next->next;
            copytail = copytail->next;
            cur->next = next;//还原原链表
            cur = next;
        }
    }
    return copyhead;
    }
}

6、判断链表中是否有环

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

示例 1:

pos表示节点的下标

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点

思路:

快慢指针,fast slow

fast = fast->next->next;

slow = slow->next;

若为环一定能相遇,返回true,否则返回false

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
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;
}

7、返回链表开始入环的第一个节点

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL

示例 1:

pos表示节点的下标

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

思路1:

快慢指针 fast slow

fast = fast->next->next;

slow = slow->next;

L为head到入环点的距离,C为环的长度,N为入环点到meet的距离

slow走的路程:L+N

fast走的路程:L+x*C+N

由于2*slow = fast

所以 L = x*C-Nx>=1,因为L不会和-N相等

当x为1时,L = C-N,meet与head相遇点即为入环点

L = x*C-N 也可以写成 L = (x-1)C+C-N,head一直在走,meet先转x-1圈,再走C-N与head相遇

/**
 * 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;
    //找meet
    while(fast&&fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            //有环,一定有入环点
            struct ListNode* meet = slow;
            //meet与head一起走
            while(1)
            {
                if(meet == head)
                {
                    return meet;
                }
                else
                {
                    meet = meet->next;
                    head = head->next;
                }
            }
        }
    }
    return NULL;
}

思路2:

newhead = meet->next;

meet->next = NULL;

这样就成链表相交问题了

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
//找链表相交节点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    while(headA)
    {
        struct ListNode* s = headB;
        while(s)
        {

            if(headA == s)
            {
                return headA;
            }
            else
            {
                s = s->next;
            }
        }
        headA = headA->next;
    }
    return NULL;
}

struct ListNode *detectCycle(struct ListNode *head)
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    //找meet
    while(fast&&fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            struct ListNode* meet = slow;
            struct ListNode* newhead = meet->next;
            meet->next = NULL;
            struct ListNode* s = getIntersectionNode(head,newhead);
            meet->next = newhead;
            return s;
        }
    }
    return NULL;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1692328.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Influence blocking maximization on networks: Models, methods and applications

abstract 由于各种社会和贸易网络的不断出现&#xff0c;网络影响力分析引起了研究者的极大兴趣。基于不同的影响力传播模型&#xff0c;人们提出了许多网络影响力最大化的新模型和方法。作为传统影响力最大化问题的延伸和扩展&#xff0c;影响力封锁最大化问题已成为研究热点&…

Python文件和数据格式化-课后作业[python123题库]

文件和数据格式化-课后作业 一、单项选择题 1、文件句柄f&#xff0c;以下是f.seek(0)作用的是&#xff1a;‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪…

spring cache(三)集成demo

一、demo 1、pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

银河麒麟服务器系统xshell连接之后主动断开,报错socket error event:32 Error:10053问题分析

银河麒麟服务器系统xshell连接之后主动断开&#xff0c;报错socket error event&#xff1a;32 Error&#xff1a;10053问题分析 一 问题描述二 系统环境三 问题分析3.1 与正常机器对比sshd文件内容以及文件权限3.2 检查同网段内是否配置多个相同的IP地址 四 后续建议 一 问题描…

每日一题《leetcode--398.随机数索引》

https://leetcode.cn/problems/random-pick-index/ 根据题目所知&#xff0c;所给的数组中有重复的元素。让我们随机输出给定的目标数字的下标索引。 typedef struct {int *sum;int length; } Solution;Solution* solutionCreate(int* nums, int numsSize) {Solution* obj (So…

数美滑块研究

周一&#xff0c;在清晨的阳光照耀下&#xff0c;逆向山脚下的小镇宁静而安详。居民们忙碌地开始一天的生活&#xff0c;而在爬虫镇子的边缘&#xff0c;一座古朴的道观显得格外神秘。 阿羊正静静地坐在青石长凳上&#xff0c;摸鱼养神。突然&#xff0c;一道清脆的声音在他耳…

【Arthas】阿里的线上jvm监控诊断工具的基本使用

关于对运行中的项目做java监测的需求下&#xff0c;Arthas则是一个很好的解决方案。 我们可以用来 1.监控cpu 现成、内存、堆栈 2.排查cpu飚高 造成原因 3.接口没反应 是否死锁 4.接口慢优化 5.代码未按预期执行 是分支不对 还是没提交&#xff1f; 6.线上低级错误 能不能不重启…

Go语言的构建标签(build tag)有何用途?

文章目录 原因解决方案示例代码总结 Go语言的构建标签&#xff08;Build Tags&#xff09;有何用途&#xff1f; 在Go语言中&#xff0c;构建标签&#xff08;Build Tags&#xff09;是一种特殊的注释&#xff0c;它用于控制Go编译器在构建代码时是否包含某些文件。这些标签可…

网页上的超链接复制到Excel中+提取出网址+如何保存

定义 超链接网页标题地址栏 使用的工具 2024年的WPS是不行的&#xff0c; 如果把知乎网页上的超链接复制到WPS中的Excel中&#xff0c;就会丢掉地址&#xff0c;只剩下网页标题 具体操作&#xff08;转载,在Excel2013上验证可行&#xff09; [1]启用【开发工具】&#xff…

HTTP content-type MIME 类型(IANA 媒体类型)

Content-Type(MediaType)&#xff0c;即是Internet Media Type&#xff0c;互联网媒体类型&#xff0c;也叫做MIME类型。在互联网中有成百上千中不同的数据类型&#xff0c;HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签&#xff0c;用于区分数据类型。最初MIME是用…

【老王最佳实践-6】Spring 如何给静态变量注入值

有些时候&#xff0c;我们可能需要给静态变量注入 spring bean&#xff0c;尝试过使用 Autowired 给静态变量做注入的同学应该都能发现注入是失败的。 Autowired 给静态变量注入bean 失败的原因 spring 底层已经限制了&#xff0c;不能给静态属性注入值&#xff1a; 如果我…

【Linux学习】深入探索进程等待与进程退出码和退出信号

文章目录 退出码return退出 进程的等待进程等待的方法 退出码 main函数的返回值&#xff1a;进程的退出码。 一般为0表示成功&#xff0c;非0表示失败。 每一个非0退出码都表示一个失败的原因&#xff1b; echo $&#xff1f;命令 作用&#xff1a;查看进程退出码。&#xf…

工具推荐:市面上有哪些带有ai问答机器人的SaaS软件

众所周知&#xff0c;SaaS&#xff08;软件即服务&#xff09;模式下的AI问答机器人已经逐渐成为企业、个人在办公、生活和学习中的辅助工具。ai问答机器人凭借高效、便捷、智能的特点&#xff0c;为用户提供了全新的交互体验。本文将推荐几款市面上好用的带有ai问答机器人的Sa…

2024年助贷CRM系统服务商汇总

数字化金融时代&#xff0c;助贷行业的发展呈现出蓬勃的态势。从各大助贷管理系统服务商的纷纷登场&#xff0c;为助贷行业提供了全方位的数字化解决方案。这些系统不仅助力企业实现业务线上化、透明化和合规化&#xff0c;更在助贷服务的专业化和贴心化上发挥着重要作用。以下…

【带你学AI】基于PP-OCR和ErnieBot的字幕提取和智能视频问答

前言 本次分享将带领大家从 0 到 1 完成一个基于 OCR 和 LLM 的视频字幕提取和智能视频问答项目&#xff0c;通过 OCR 实现视频字幕提取&#xff0c;采用 ErnieBot 完成对视频字幕内容的理解&#xff0c;并回答相关问题&#xff0c;最后采用 Gradio 搭建应用。本项目旨在帮助初…

UE5 像素流web 交互2

进来点个关注不迷路谢谢&#xff01; ue 像素流交互多参数匹配 主要运用像素流的解析json 状态&#xff1a; 测试结果&#xff1a; 浏览器控制台&#xff1a; 接下来编写事件传递 关注下吧&#xff01;

C语言 变量的存储类型

今天 我们来说变量的存储类型 变量的存储类型是指系统为变量分配存储区域的方式。 决定着变量存储空间在哪里分配&#xff0c;和变量的生存期、作用域存在着一定联系。 动态存储 函数调用发生时系统根据函数定义的需要动态为其分配的一个栈区&#xff0c;函数调用结束时释放…

刷代码随想录有感(76):回溯算法——全排列

题干&#xff1a; 代码&#xff1a; class Solution { public:vector<int> tmp;vector<vector<int>> res;void backtracking(vector<int> nums, vector<int> used){if(tmp.size() nums.size()){res.push_back(tmp);return;}for(int i 0; i &l…

【Linux】POSIX线程库——线程控制

目录 1.线程创建方法 例&#xff1a;多线程创建 2.线程终止 2.1 return nulptr; 2.2 pthread_exit(nullptr); 3. 线程等待 3.1 等待原因 3.2 等待方法 线程终止的返回值问题 4.线程取消 5. 线程分离 5.1 分离原因 5.2 分离方法 6.封装线程 用的接口是POSIX线程库…

(Java企业 / 公司项目)配置Linux网络-导入虚拟机

公司给了我一个IP地址 &#xff0c;提供了一个虚拟机或者自己搭建虚拟机&#xff0c;还有提供登录的账号密码 可以查看我之前的文章 VMware Workstation Pro 17虚拟机超级详细搭建&#xff08;含redis&#xff0c;nacos&#xff0c;docker, rabbitmq&#xff0c;sentinel&…