【Hello Algorithm】链表相关算法题
本篇博客介绍: 介绍下链表相关的算法题
链表相关算法题
- 快慢指针
- 回文结构链表
- 将单向链表按某值划分为左边小,中间相等,右边大的形式
- 复制带随机指针的链表
链表相关的算法题其实都算不上难
我们真正要考虑的是一些边界问题 事实上链表题就是在锻炼我们的处理边界能力
其次我们要强调的一点是 在笔试和面试中 我们的解题思路是不同的
在笔试中我们一般追求快速解题 只需要考虑时间复杂度 (一般空间复杂度上不会卡你)
但是在面试中 我们必须要在保证时间复杂度的情况下考虑空间复杂度 因为面试官会根据你写出的代码来判断你对于这个问题真正理解多少 有没有达到要求
快慢指针
比如说现在题目要求我们找出一个链表的中点
常规的解法就是 我们数一下链表的长度是多少
数出链表的长度之后除以二 之后使用指针一步步遍历到中点位置即可
快慢指针法解决中点问题
我们可以设计两个指针 快指针和慢指针
慢指针每次走一步
快指针每次走两步
我们可以通过调整快慢指针谁先走来调整中点
当然其中也有一些边界问题 比如说空指针的引用需要注意
lc上原题的连接如下
链表的中间节点
C++代码如下
class Solution {
public:ListNode* middleNode(ListNode* head) {if (head -> next == nullptr){return head;}ListNode* slow = head;ListNode* fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;} return slow;}
};
此外 快慢指针还能解决链表第K个节点之类的问题 思路同上
回文结构链表
正读和反读都相同的字符序列为回文
比如说下面的这一行字符
1 2 3 2 1
这就是一个回文结构
但是如果我们改变下最后节点的值 变成
1 2 3 2 2
这就不是一个回文结构了
判断它是不是一个回文结构我们也有多种做法
如果是在笔试中 我们可以选择最简单的 使用一个栈结构去解
具体解法为
- 我们首先定义一个栈结构
- 从头开始遍历所有的链表值 将所有的链表值放到栈结构中
- 这样子我们就得到了一个逆序的链表值
- 于是我们只要再次从头开始遍历整个链表 并且与栈中的逆序值做对比即可
题目连接和代码表示如下
回文链表
class Solution {
public:bool isPalindrome(ListNode* head) {if (head->next == nullptr){return true;}stack<int> st;ListNode* cur = head;while(cur){st.push(cur->val);cur = cur->next;}cur = head;while(!st.empty()){if (st.top() == cur->val){st.pop();cur = cur->next;}else {return false;}}return true;}
};
但是上面的解法仅限于笔试中 如果在面试中我们遇到了这个问题肯定是面试官想考查我们空间复杂度为O1的解法
其实思路也很简单
- 找到链表的左中点 并且指向空
- 翻转整个链表的右半部分(以左中点为结束位置)
- 设置两个指针 分别从左右开始对比值 如果全部相同 最后返回true 反之返回false
- 最后一定要记得将链表复原
代码表示如下
class Solution {
public:bool isPalindrome(ListNode* head) {if (head->next == nullptr){return true;}// 0 设置返回值bool ret = true;// 1 找出链表的左中点ListNode* slow = head;ListNode* fast = head;while(fast->next && fast->next->next){fast = fast->next->next;slow = slow->next;}// 2 设置左右中点ListNode* leftmidpoint = slow; ListNode* rightmidpoint= slow->next; // 排除掉了一个节点的情况 不可能为空// 3 开始翻转ListNode* n1 = leftmidpoint;ListNode* n2 = rightmidpoint;ListNode* n3 = rightmidpoint->next; // 有可能为空leftmidpoint->next = nullptr;while(1){n2 ->next = n1;n1 = n2;n2 = n3;if (n3){n3 = n3->next;}else {break;}}ListNode* righthead = n1;ListNode* cur1 = head;ListNode* cur2 = righthead;while (cur1 != nullptr){if (cur1->val == cur2->val){cur2 = cur2->next;cur1 = cur1->next;}else{ret = false;break;}}// 4 还原链表 leftmidpoint->next = rightmidpoint;n1 = righthead;n2 = righthead->next;righthead->next = nullptr;if (n2 == leftmidpoint){return ret;}n3 = n2->next;while(1){ n2->next = n1;n1 = n2;n2 = n3;if (n3 == leftmidpoint){break;}else {n3 = n3->next;}}return ret;;}
};
将单向链表按某值划分为左边小,中间相等,右边大的形式
题目要求如下
链接:https://www.nowcoder.com/questionTerminal/04fcabc5d76e428c8100dbd855761778
来源:牛客网
给定一个链表,再给定一个整数 pivot,请将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于 pivot 的节点, 右边部分都是大于 pivot 的节点。
除此之外,对调整后的节点顺序没有更多要求。
解题思路上其实没有难点
- 我们设置六个指针 分别是小头 小尾 等头 等尾 大头 大尾即可
- 之后遍历链表 更新上面的指针
- 最后让这些指针相连
- 有一个难点就是我们要考虑有区域为空的情况
代码表示如下
# include <bits/stdc++.h>
using namespace std;struct list_node{int val;struct list_node * next;
};
#define Node list_node
int pivot;list_node * input_list(void)
{int n, val;list_node * phead = new list_node();list_node * cur_pnode = phead;scanf("%d%d", &n, &pivot);for (int i = 1; i <= n; ++i) {scanf("%d", &val);if (i == 1) {cur_pnode->val = val;cur_pnode->next = NULL;}else {list_node * new_pnode = new list_node();new_pnode->val = val;new_pnode->next = NULL;cur_pnode->next = new_pnode;cur_pnode = new_pnode;}}return phead;
}
void insertHead(Node *head, Node* x) {if(x==NULL || head==NULL) return;Node* last = head->next;head->next = x;x ->next = last;
}list_node * list_partition(list_node * head, int pivot)
{//在下面完成代码if(head==NULL || head->next ==NULL)return head;Node dummy_head;list_node *first = head;list_node lt,gt,eq;Node *l = <,*g = >, *e = &eq;lt.next = gt.next = eq.next = NULL;while(first) {if(first ->val == pivot) {e ->next = first,first = first->next,e = e->next,e->next = NULL;}else if(first->val > pivot) {g ->next = first,first = first->next, g = g->next,g->next = NULL;}else {l->next = first,l = l->next,first = first->next, l->next = NULL;}}e->next = gt.next;l->next = eq.next;first = lt.next;while(first) {printf("%d ", first->val);first = first->next;}return lt.next;}int main ()
{list_node * head = input_list();list_partition(head, pivot);return 0;
}
复制带随机指针的链表
题目描述可以直接参考leetcode
我这里就不水字数了
复制随机指针的链表
这个题目在我刚刚接触C++的时候其实也做过一次 博客连接如下
复制带随机指针的链表
这个题目的难点其实只有一个
如何确定随机指针指向的位置 如果随机指针指向的位置一定是向后的话我们倒是可以使用数步数的方式来实现 可要是随机指针指向的是前面呢? 通过遍历去找嘛?
这样子时间复杂度直接上N方了 肯定是过不了的
那么我们解决这个难点的思路有两个
- 使用哈希表 哈希表的KEY值对应原节点 VALUE值对应复制的节点 这样子我们只要找到原来的节点的随机指针 再到哈希表中找对应的VALUE值即可
- 因为随机指针本质上就是指向该链表中的某一个节点 所以说只要我们能够确定该链表中任意一个节点的相对位置 我们就能够找到复制后的随机指针应该指向哪里 于是我们可以选择在原链表的每个节点后面加上一个复制的节点 这样子我们通过原链表的随机指针找到对应的节点后下一个节点就是我们复制节点的随机指针应该指向的节点了
这两种方法的时间复杂度都是O(N) 但是第一种方法的空间复杂度要高一些
所以说我们在面试中要选用第二种方法 在笔试中可以选择第一种方法
代码表示如下
class Solution {
public:Node* copyRandomList(Node* head) {if (head == nullptr){return nullptr;}// 1 复制节点到原节点后Node* cur = head;Node* NEXT = nullptr; // null?while (cur){NEXT = cur -> next;cur -> next = new Node(cur->val); cur -> next -> next = NEXT;cur = NEXT;}// 2 随机指针开始拷贝 Node* cur2 = head->next;cur = head;while(cur){cur2 = cur->next;if (cur->random){cur2->random = cur->random->next;}else {cur2->random = nullptr;}cur = cur->next->next;}// 3 分离出复制的节点cur2 = head->next;cur = head;NEXT = nullptr;Node* NEXT2 = nullptr;head = cur2;while(cur){NEXT = cur->next->next;if (NEXT== nullptr){NEXT2 = nullptr;}else {NEXT2 = NEXT->next;}cur->next = NEXT;cur2->next = NEXT2;cur = NEXT;cur2 = NEXT2;}return head;}
};
相关文章:
【Hello Algorithm】链表相关算法题
本篇博客介绍: 介绍下链表相关的算法题 链表相关算法题 快慢指针回文结构链表将单向链表按某值划分为左边小,中间相等,右边大的形式复制带随机指针的链表 链表相关的算法题其实都算不上难 我们真正要考虑的是一些边界问题 事实上链表题就是在…...
自动化管理管理工具----Ansible
目录 编辑 一、Ansible概念 1.1特点 二、工作机制(日常模块) 2.1 核心程序 三、Ansible 环境安装部署 四、ansible 命令行模块 4.1command 模块 4.2shell 模块 4.3cron 模块 4.4user 模块 4.5group 模块 4.6copy模块 4.7file模块 4.8ho…...
深入理解css3背景图边框
border-image知识点 重点理解 border-image-slice 设置的值将边框背景图分为9份,图像中间的舍弃,其他部分图像对应边框的相应区域放置,上右下左四角固定,border-image-repeat设置的是除四角外其他部分的显示方式。 截图来自菜鸟教…...
【rust/egui】(六)看看template的app.rs:TextEdit
说在前面 rust新手,egui没啥找到啥教程,这里自己记录下学习过程环境:windows11 22H2rust版本:rustc 1.71.1egui版本:0.22.0eframe版本:0.22.0上一篇:这里 TextEdit 文本编辑框 其定义为&#…...
Redis内存空间预估与内存优化策略:保障数据安全与性能的架构实践
推荐阅读 AI文本 OCR识别最佳实践 AI Gamma一键生成PPT工具直达链接 玩转cloud Studio 在线编码神器 玩转 GPU AI绘画、AI讲话、翻译,GPU点亮AI想象空间 资源分享 史上最全文档AI绘画stablediffusion资料分享 AI绘画关于SD,MJ,GPT,SDXL百科全书 「java、python面试题」…...
【zookeeper】zookeeper集群安装
环境规划 实际的生产使用中,我们一般推荐搭建奇数多节点的zookeeper集群,如3/5/7。在本次测试中,我使用了centos7 三台服务器搭建,复用了我搭建k8s集群的环境,如下表。 IPhostname192.168.2.140k8s-m1192.168.2.141k…...
CUDA小白 - NPP(2) - Arithmetic and Logical Operations(1)
cuda小白 原文链接 NPP GPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus,…...
计算机视觉-LeNet
目录 LeNet LeNet在手写数字识别上的应用 LeNet在眼疾识别数据集iChallenge-PM上的应用 LeNet LeNet是最早的卷积神经网络之一。1998年,Yann LeCun第一次将LeNet卷积神经网络应用到图像分类上,在手写数字识别任务中取得了巨大成功。LeNet通过连续使用…...
Java 复习笔记 - 面向对象篇
文章目录 一,面向对象概述二,类和对象(一)类和对象的概述(二)定义类的补充注意事项 三,封装四,就近原则和this关键字(一)就近原则(二)…...
行业追踪,2023-08-31
自动复盘 2023-08-31 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...
科技资讯|苹果发布新专利:可在车内定位苹果的智能设备
根据美国商标和专利局近期公示的清单,苹果公司获得了一项名为《车内定位移动设备的系统和方式》专利,概述了在车内狭窄空间内如何定位 iPhone 等移动设备。 Find My 服务现阶段没有使用 UWB 来追踪 iPhone 或者 iPad,而是依赖 GPS 等相关辅…...
浅析Linux SCSI子系统:IO路径
文章目录 概述scsi_cmd:SCSI命令result字段proto_op字段proto_type字段 SCSI命令下发scsi_request_fnscsi_dev_queue_readyscsi_host_queue_ready SCSI命令响应命令请求完成的软中断处理 相关参考 概述 SCSI子系统向上与块层对接,由块层提交的对块设备的…...
linux系统(centos、Ubuntu、银河服务器)备份
制作u盘启动盘 下载usblive系统镜像 Get Kali | Kali Linux 下载u盘启动工具 balenaEtcher - Flash OS images to SD cards & USB drives 点击下载,等待下载完成 双击安装,等待安装完成 双击 启动 选择镜像 选择U盘 开始烧录 等地制作完成 进入…...
堆栈深度超过限制
报错:Cause: com.kingbase8.util.KSQLException: 错误: 堆栈深度超过限制 Hint: 在确定了平台的堆栈深度限制是足够大后,增加配置参数 "max_stack_depth"的值(当前值为2048kB).; 错误: 堆栈深度超过限制 Hint: 在确定了平台的堆栈深度限制是足…...
Linux ptrace系统调用
文章目录 一、ptrace 简介二、ptrace 参数request2.1 PTRACE_TRACEME2.2 PTRACE_PEEKTEXT, PTRACE_PEEKDATA2.3 PTRACE_PEEKUSER2.4 PTRACE_POKETEXT, PTRACE_POKEDATA2.5 PTRACE_POKEUSER2.6 PTRACE_GETREGS, PTRACE_GETFPREGS2.7 PTRACE_GETREGSET2.8 PTRACE_SETREGS, PTRACE…...
CSDN每日一练 |『贝博士发奖金』『Longest Continuous Increasing Subsequence』『最小差值』2023-09-01
CSDN每日一练 |『贝博士发奖金』『Longest Continuous Increasing Subsequence』『最小差值』2023-09-01 一、题目名称:贝博士发奖金二、题目名称:Longest Continuous Increasing Subsequence三、题目名称:最小差值一、题目名称:贝博士发奖金 时间限制:1000ms内存限制:25…...
二维数组创建方式比较
暑假跟着地质队去跑山了,到现在还没结束,今天休息的时候突然刷到了一篇关于C二维数组创建方面的文章,我觉得还是非常不错滴,就将其中提到的新方法和我已经使用过的三种方法进行了比较,发现该方法提高了二维数组的分配、…...
安达发|富士康科技集团利用自动排程APS软件打造智慧工厂
富士康科技集团作为全球领先的3C产品研发制造企业,近年来积极布局智能制造领域,通过引入先进的自动化排程系统(APS),成功打造了智慧工厂,提高了生产质量与效率,降低了生产成本。 富士康集团自2019年下半年提出在观澜厂区建立数字可…...
云计算在大数据分析中的应用与优势
文章目录 云计算在大数据分析中的应用云计算在大数据分析中的优势云计算在大数据分析中的示例未来发展和拓展结论 🎉欢迎来到AIGC人工智能专栏~云计算在大数据分析中的应用与优势 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨博客主页:IT陈寒的博客&…...
linux————ELK(日志收集系统集群)
目录 一、为什么要使用ELK 二、ELK作用 二、组件 一、elasticsearch 特点 二、logstash 工作过程 INPUT(输入) FILETER(过滤) OUTPUTS(输出) 三、kibana 三、架构类型 ELK ELKK ELFK ELFKK EFK 四、构建ELk集群…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
