【每日一题】2009考研数据结构 - 求倒数第k个数的值

已知一个带有表头结点的单链表,结点结构为 datalink。假设该链表只给出了头指针 list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第 k 个位置上的结点(k 为正整数)。

要求:

  1. 若查找成功,算法输出该结点的 data 域的值,并返回 1
  2. 若查找失败,则返回 0

题目分析与设计思想

给定一个单链表,我们的目标是找到链表中倒数第 k 个结点的数据值。在链表中,由于无法通过下标直接访问倒数第 k 个元素,我们需要采取其他方法。最简单的方法是遍历两次链表:第一次获取链表的长度,第二次找到倒数第 k 个结点。然而,这种方法的时间复杂度为 O(n + n) = O(2n),可以进一步优化。

为了提高效率,我们可以使用双指针法,先让一个指针先走 k 步,然后两个指针一起移动,直到第一个指针到达链表末尾时,第二个指针刚好指向倒数第 k 个节点。这样实现的算法只需遍历一次链表,时间复杂度为 O(n)


实现步骤

  1. 初始化两个指针 leftcur,都指向链表头部。
  2. cur 指针向前移动 k 步。如果在这过程中 cur 指针提前到达链表末尾,说明链表长度不足 k,直接返回 0
  3. cur 指针顺利移动 k 步且没有到达链表末尾,则继续让 leftcur 两个指针同时移动,直到 cur 指针到达链表末尾。
  4. 此时,left 指针指向的结点即为倒数第 k 个结点,输出该结点的 data 值并返回 1

代码实现(双指针)

以下是代码实现,并附有详细注释:

#include "bits/stdc++.h"
using namespace std;

// 定义链表节点结构
struct Node {
    int data;      // 节点数据
    Node* next;    // 指向下一个节点
};

// 创建新节点的辅助函数
Node* createNode(int data) {
    Node* node = new Node();  // 分配内存给新节点
    node->data = data;        // 设置节点数据
    node->next = nullptr;     // 初始化下一节点为null
    return node;
}

// 查找倒数第k个节点的主函数
int getKData(Node* head, int k) {
    Node* left = head; // 第一个指针
    int t = k;
    Node* cur = head;  // 第二个指针

    // cur指针向前移动k步
    while (t-- && cur != nullptr) {
        cur = cur->next;
    }
    
    // 如果链表长度小于k,则返回0
    if (t != -1) return 0;

    // 两个指针一起移动
    while (cur != nullptr) {
        cur = cur->next;
        left = left->next;
    }
    return left->data;
}

int main() {
    // 创建测试链表
    Node* head = createNode(1);
    Node* cur = head;
    for (int i = 2; i <= 7; i++) {
        Node* newNode = createNode(i);
        cur->next = newNode;
        cur = newNode;
    }
    
    // 打印链表
    cur = head; // 从头节点开始
    while (cur != nullptr) {
        cout << cur->data << " "; // 打印当前节点的数据
        cur = cur->next; // 移动到下一个节点
    }
    cout << endl;
    
    // 查找倒数第2个节点
    int value = getKData(head, 2);
    cout << value << endl; // 输出结果
    
    return 0;
}

代码解析

1. 创建链表

main 函数中,我们首先创建一个单链表作为测试用例,包含从 17 的数据结点。

2. 双指针查找倒数第 k 个节点

getKData 函数中,我们通过移动 cur 指针 k 步来预留倒数位置。随后将 curleft 指针同时移动,直至 cur 指向 nullptr。此时 left 就指向了倒数第 k 个节点。

时间复杂度与空间复杂度分析

  • 时间复杂度O(n),因为最多需要遍历链表一次。
  • 空间复杂度O(1),因为只使用了常数空间来存储两个指针。

代码实现(两次遍历)

// 查找倒数第k个节点的两次遍历法实现
int getKDataTwoPass(Node* head, int k) {
    Node* cur = head;
    int length = 0;

    // 第一次遍历:计算链表长度
    while (cur != nullptr) {
        length++;
        cur = cur->next;
    }

    // 如果k大于链表长度,返回0
    if (k > length) return 0;

    // 计算倒数第k个节点的位置(从头开始的正数位置)
    int targetIndex = length - k;

    // 第二次遍历:找到正数第targetIndex个节点
    cur = head;
    for (int i = 0; i < targetIndex; i++) {
        cur = cur->next;
    }

    return cur->data;
}

代码讲解

  1. 第一次遍历:遍历整个链表,计算链表的总长度 length
  2. 长度检查:判断 k 是否大于链表的长度。如果是,则返回 0,因为倒数第 k 个节点不存在。
  3. 计算目标位置:根据总长度和 k 值计算目标节点的正数位置 targetIndex = length - k
  4. 第二次遍历:重新从链表头部开始遍历,到达 targetIndex 位置时停止,即为倒数第 k 个节点,返回该节点的 data

时间复杂度

  • 时间复杂度O(n),需要两次遍历链表,每次遍历的时间复杂度为 O(n),因此整体复杂度为 O(n + n) = O(2n)
  • 空间复杂度O(1),只使用了常数空间来存储变量。

方法比较

  1. 双指针法

    • 优点:只需遍历一次链表,时间复杂度为 O(n),更高效。
    • 缺点:需要多一点的代码逻辑处理。
  2. 两次遍历法

    • 优点:逻辑简单,第一次遍历获取链表长度,第二次定位倒数位置。
    • 缺点:时间复杂度为 O(2n),较慢。

在这里插入图片描述

总结

本题通过使用双指针法,避免了两次遍历链表,实现了更高效的倒数第 k 个结点查找。希望本文的详细解析帮助大家更好地理解链表操作和双指针的用法。该方法是一种在链表中查找倒数位置的常用技巧,对理解链表的操作非常有帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ELF加载,进程地址空间与可执行程序的关系

1&#xff0c;可执行程序的格式 粗略概况 操作系统要如何认识可执行程序&#xff1f;我们的可执行程序是有格式的&#xff1a; 用指令size 加可执行程序名&#xff1a; 其中test就是代码块&#xff0c;data就是数据块&#xff0c;不仅可执行程序有格式&#xff0c;动态库&am…

超实惠的租借服务器训练深度学习方法

1. 必备软件 1.1 Xftp和Xshell 通过百度网盘分享的文件&#xff1a;Niha 链接&#xff1a;https://pan.baidu.com/s/1uHLme7H9SL2C-ZhFr107gA?pwdnadb 提取码&#xff1a;nadb xftp用于连接服务器, 传输本地文件到服务器上面去。 xshell用于连接服务器进行命令操作 2 恒源…

蓝桥杯-网络安全比赛题目-遗漏的压缩包

小蓝同学给你发来了他自己开发的网站链接&#xff0c; 他说他故意留下了一个压缩包文件&#xff0c;里面有网站的源代码&#xff0c; 他想考验一下你的网络安全技能。 &#xff08;点击“下发赛题”后&#xff0c;你将得到一个http链接。如果该链接自动跳转到https&#xff0c;…

MongoDB笔记03-MongoDB索引

文章目录 一、前言1.1 概述1.2 MongoDB索引使用B-Tree还是BTree&#xff1f;1.3 B 树和 B 树的对比1.4 总结 二、索引的类型2.1 单字段索引2.2 复合索引2.3 其他索引 三、索引的管理操作3.1 索引的查看3.2 索引的创建3.2.1 单字段索引3.2.2 复合索引 3.3 索引的移除3.3.1 指定索…

【Android】时区规则库tzdata更新

1 背景&#xff1a; 最近我遇到墨西哥城时区&#xff0c;会出现夏令时&#xff0c;而墨西哥城在2022年底都已经取消夏令时了。 看起来是要更新RK3588上的时区库&#xff0c;我的还是2021a&#xff0c;而现在都已经2024年了 这样能看版本号&#xff1a; cat /system/usr/sha…

网络初始:TCP/IP 五层协议模型 网络通信基本流程

目录 1. 名词解释 1.1 局域网 1.2 广域网 1.3 交换机 1.4 IP 地址 1.5 端口号 2. 协议 2.1 认识协议 2.2 五元组 3. 协议分层 3.1 分层的作用 3.2 OSI 七层网络模型 & TCP/IP 五层(四层)协议模型 4. TCP/IP 五层(四层)网络模型 4.1 物理层 4.2 数据链路层 4…

小新学习k8s第六天之pod详解

一、资源限制 Pod是k8s中的最小的资源管理组件&#xff0c;pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。k8s中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的&#xff0c;例如&#xff0c;用于管理Pod运行的StatefulSet和Deployment等…

安利一款超6K+ star的可拖放响应式灵活的网格布局Gridstack.js

Gridstack.js是一个现代JavaScript&#xff08;或Typescript&#xff09;库&#xff0c;旨在帮助开发人员快速构建交互式和响应式的布局。以下是对Gridstack.js的详细介绍&#xff1a; 一、主要特点 灵活的网格布局&#xff1a;Gridstack.js允许开发者轻松地创建和管理网格布局…

接口测试基础 --- 什么是接口测试及其测试流程?

接口测试是指针对软件系统的接口进行测试的过程&#xff0c;主要是验证系统之间的数据传输和通信是否正常、功能是否正确。接口测试主要关注接口的输入、输出以及相应的逻辑关系&#xff0c;而不关注底层实现细节。接口测试可以帮助开发团队发现和解决与接口相关的问题&#xf…

1分钟解决Excel打开CSV文件出现乱码问题

一、编码问题 1、不同编码格式 CSV 文件有多种编码格式&#xff0c;如 UTF - 8、UTF - 16、ANSI 等。如果 CSV 文件是 UTF - 8 编码&#xff0c;而 Excel 默认使用的是 ANSI 编码打开&#xff0c;就可能出现乱码。例如&#xff0c;许多从网络应用程序或非 Windows 系统生成的 …

python基础(1)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;初识python&#xff0c;环境配置&#xff0c;编程基础以及数据类型_哔哩哔哩_bilibili 一、什么是python Python 是一种高级、解释型、通用编程语…

USB 设备数据安全管理解决方案

在当今数字化的办公环境中&#xff0c;USB 设备的广泛使用为企业和组织带来了便捷&#xff0c;但同时也隐藏着巨大的数据泄露风险。许多企业和机构都曾因 USB 设备使用不当而遭受严重损失。 一方面&#xff0c;员工可能会无意或有意地使用未经授权的 USB 设备接入公司网络。这…

【UE5】一种老派的假反射做法,可以用于移动端,或对反射的速度、清晰度有需求的地方

没想到大家这篇文章呼声还挺高 这篇文章是对它的详细实现&#xff0c;建议在阅读本篇之前&#xff0c;先浏览一下前面的文章&#xff0c;以便更好地理解和掌握内容。 这种老派的假反射技术&#xff0c;适合用于移动端或对反射效果的速度和清晰度有较高要求的场合。该技术通过一…

Flink滑动窗口(Sliding)中window和windowAll的区别

滑动窗口的使用&#xff0c;主要是计算&#xff0c;在reduce之前添加滑动窗口&#xff0c;设置好间隔和所统计的时间&#xff0c;然后再进行reduce计算数据即可。 窗口设置好时间间隔&#xff0c;和处理时间窗口的时间&#xff0c;比如将滑动窗口的时间间隔都设置为5s,处理时间…

基于YOLO11/v10/v8/v5深度学习的煤矿传送带异物检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

Golang--文件操作

1、文件 文件&#xff1a;文件用于保存数据&#xff0c;是数据源的一种 os包下的File结构体封装了对文件的操作&#xff08;记得包os包&#xff09; 2、File结构体--打开文件和关闭文件 2.1 打开文件 打开文件&#xff0c;用于读取&#xff08;函数&#xff09;&#xff1a; 传…

BSAchongsds、

一、 ## 统计基因组整体信息 srun -A 2022099 -p Debug -n 2 -N 1 seqkit stats ~/yiyaoran/workspace/06.BSRseq/guo_BSR_pipline/ref/genome.fasta > genome.allstatcat genome.allstat 文件名 格式 类型 序列数量 总长度 最小长度 平均长…

聊一聊Elasticsearch的基本原理与形成机制

1、搜索引擎的基本原理 通常搜索引擎包括&#xff1a;数据采集、文本分析、索引存储、搜索等模块&#xff0c;它们之间的协作流程如下图&#xff1a; 数据采集模块负责采集需要搜索的数据源。 文本分析模块是将结构化数据中的长文本切分成有实际意义的词&#xff0c;这样用户…

**AI的三大支柱:神经网络、大数据与GPU计算的崛起之路**

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Python | Leetcode Python题解之第542题01矩阵

题目&#xff1a; 题解&#xff1a; class Solution:def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:m, n len(matrix), len(matrix[0])# 初始化动态规划的数组&#xff0c;所有的距离值都设置为一个很大的数dist [[10**9] * n for _ in range(m)]…