链表经典面试题

1 回文链表

1.1 判断方法
  1. 第一种(笔试):
    • 链表从中间分开,把后半部分的节点放到栈中
    • 从链表的头结点开始,依次和弹出的节点比较
  2. 第二种(面试):
    • 反转链表的后半部分,中间节点的下一节点指向空
    • 两个指针分别从链表的头和尾出发比较
    • 直到左边节点到空或两个节点都到空停止
    • 判断结果出来后,要把链表后半部分反转回去。
1.2 代码实现
ublic class IsPalindromList {public static class Node {public int val;public Node next;public Node(int data) {val = data;next = null;}}public static boolean isPalindrom1(Node head) {if (head == null || head.next == null) {return true;}Stack<Node> stack = new Stack<>();Node mid = head;Node fast = head;while (fast.next != null && fast.next.next != null) {mid = mid.next;fast = fast.next.next;}while (mid.next != null) {mid = mid.next;stack.add(mid);}Node i = head;boolean ans = true;while (stack.size() != 0) {if (i.val != stack.pop().val) {ans = false;break;}i = i.next;}return ans;}public static boolean isPalindrom2(Node head) {if (head == null || head.next == null) {return true;}// 找到中间节点Node mid = head;Node fast = head;while (fast.next != null && fast.next.next != null) {mid = mid.next;fast = fast.next.next;}Node cur = mid;// 后边段链表反转Node pre = null;Node next = null;while (cur != null) {next = cur.next;cur.next = pre;pre = cur;cur = next;}Node left = head;Node right = pre;boolean ans = true;while (left != null && right != null) {if (left.val != right.val) {ans = false;break;}left = left.next;right = right.next;}cur = pre;pre = null;next = null;while (cur != null) {next = cur.next;cur.next = pre;pre = cur;cur = next;}return ans;}public static void main(String[] args) {Node head = new Node(0);head.next = new Node(1);head.next.next = new Node(2);head.next.next.next = new Node(2);head.next.next.next.next = new Node(1);head.next.next.next.next.next = new Node(0);System.out.println(isPalindrom2(head));System.out.println(isPalindrom1(head));}}

2 荷兰国旗

链表的荷兰国旗问题,给定一个链表头节点,一个划分值

  • 把链表中小于划分值的放在左边
  • 等于划分值的放在中间
  • 大于划分值的放在右边。
2.1 解决方法

(其实我第一次写的时候第二种方法比第一种方法写的快,因为思路简单,不绕。)

  1. 第一种(笔试):
    • 把链表的所有节点放在一个节点数组中
    • 对这个数组做partition过程
    • 之后把数组每个节点连起来
  2. 第二种(面试):
    • 定义有六个节点,分别代表:大于、等于和小于区域的头和尾
    • 链表开始遍历,比划分值小的连在小于区域下方,同时断开节点和之前链表的关系,指向空
    • 等于和大于同理
    • 遍历完链表之后,开始把小于区域的尾巴和等于区域的头连接,等于区域的尾巴和大于区域的头连接
2.2 代码实现
public class SmallEqualBig {public static class Node {public int val;public Node next;public Node(int val) {this.val = val;next = null;}}public static Node listPartition1(Node head, int pivot) {if (head == null || head.next == null) {return head;}int index = 1;Node cur = head;while (cur.next != null) {index++;cur = cur.next;}Node[] arr = new Node[index];cur = head;for (int i = 0; i < arr.length; i++) {arr[i] = cur;cur = cur.next;}partition(arr,pivot);for (index = 1; index != arr.length; index++) {arr[index - 1].next = arr[index];}arr[index - 1].next = null;return arr[0];}public static Node listPartition2(Node head, int pivot) {if (head == null || head.next == null) {return head;}Node smallHead = null;Node smallTail = null;Node equalHead = null;Node equalTail = null;Node bigHead = null;Node bigTail = null;Node next = null;while (head != null) {next = head.next;head.next = null;if (head.val < pivot) {if (smallHead == null) {smallHead = head;smallTail = head;}else {smallTail.next = head;smallTail = smallTail.next;}} else if (head.val == pivot) {if (equalHead == null) {equalHead = head;equalTail = head;}else {equalTail.next = head;equalTail = equalTail.next;}}else {if (bigHead == null) {bigHead = head;bigTail = head;}else {bigTail.next = head;bigTail = bigTail.next;}}head = next;}if (smallTail != null) {smallTail.next = equalHead;equalTail = equalTail == null ? smallTail : equalTail;}if (equalTail != null) {equalTail.next = bigHead;}return smallHead == null ? (equalHead == null ? bigHead : equalHead) : smallHead;}private static void partition(Node[] arr, int pivot) {int small = -1;int big = arr.length;int index = 0;while (index < big) {if(arr[index].val < pivot) {swap(arr, index++, ++small);} else if (arr[index].val > pivot) {swap(arr, index++, --big);}else {index++;}}}private static void swap(Node[] arr, int i, int j) {Node temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String[] args) {Node head = new Node(9);head.next = new Node(1);head.next.next = new Node(2);head.next.next.next = new Node(6);head.next.next.next.next = new Node(4);head.next.next.next.next.next = new Node(5);head.next.next.next.next.next.next = new Node(2);Node node = listPartition1(head, 2);while (node != null) {System.out.print(node.val + " ");node = node.next;}System.out.println();Node head2 = new Node(9);head2.next = new Node(1);head2.next.next = new Node(2);head2.next.next.next = new Node(6);head2.next.next.next.next = new Node(4);head2.next.next.next.next.next = new Node(5);head2.next.next.next.next.next.next = new Node(2);Node node1 = listPartition2(head2, 2);while (node1 != null) {System.out.print(node1.val + " ");node1 = node1.next;}}
}

3 复制链表

复制特殊链表,单链表中加了个rand指针,可能指向任意一个节点,也可能指向null

给定这个链表的头节点,完成链表的复制

返回复制的新链表的头节点。时间复杂度O(N),额外空间复杂度O(1)

3.1 解决方法
  1. 方法一(笔试):

    • 用HashMap来解决,key是原数组节点,value是复制的数组节点
  2. 方式二(面试):

    • 将复制的新节点插入到原数组的节点中,如1–>2–>3,变成1–>(copy)1–>2–>(copy)2–>3–>(copy)3

    • 复制节点的rand指针指向就是原数组的节点的rand指针的下一节点(下图所示)

    • 把复制数组拿出来的时候注意复制数组连起来还要把原数组连起来

      image-20231109141535414

3.2 代码实现
public class CopyListWithRandom {public static class Node {public int val;public Node next;public Node rand;public Node(int val) {this.val = val;}}// map方法public static Node copyListWithRandom(Node head) {if (head == null) {return null;}HashMap<Node, Node> map = new HashMap<>();Node cur = head;while (cur != null) {map.put(cur, new Node(cur.val));cur = cur.next;}Node ans = map.get(head);cur = head;while (cur != null) {map.get(cur).next = map.get(cur.next);map.get(cur).rand = map.get(cur.rand);cur = cur.next;}return ans;}// 不借助容器public static Node copyListWithRandom2(Node head) {if (head == null) {return null;}Node cur = head;Node next = null;while (cur != null) {next = cur.next;cur.next = new Node(cur.val);cur.next.next = next;cur = next;}Node copyNode = null;cur = head;while (cur != null) {copyNode = cur.next;copyNode.rand = cur.rand == null ? null : cur.rand.next;cur = copyNode.next;}Node ans = head.next;cur = head;while (cur != null) {next = cur.next.next;copyNode = cur.next;copyNode.next = next == null ? null : next.next;cur.next = next;cur = next;}return ans;}public static void main(String[] args) {Node head = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);head.next = node2;node2.next = node3;head.rand = node3;node2.rand = head;Node node = copyListWithRandom(head);while (node != null) {System.out.println(node.val + " ");System.out.println(node == head);node = node.next;head = head.next;}}
}

4 链表相交

给定两个可能有环也可能无环的单链表,给定头节点1和头节点2.
请实现一个函数,如果两个链表相交,请返回相交的第一个节点,如果不相交,返回null
时间复杂度O(N),额外空间复杂度O(1)

4.1 解决方法
  1. 先判断两个链表是否有环
  2. 两个都无环
    • 如果两个链表的末尾节点相等,那么就是相交的,用指针先把长的链表走完两个链表的差值后,两个链表开始同时走,直到两个节点相等,就是相交的点
    • 如果末尾节点不相等,那么两个链表不相交
  3. 一个有环一个无环:两个链表不会有相交点
  4. 两个都有环
    • 判断两个链表进环的第一个节点是否是相同的
    • 相同:相交,且相交点就在无环的部分中,参考2
    • 不相同:从一个链表的入环节点开始找,如果找到了第二个链表的入环节点,那么就相交,返回两个入环节点任意一个,如果转一圈到第一个链表的入环节点还没有找到第二个入环节点,此时不相交。
4.2代码实现
public class FindFirstIntersectNode {public static class Node {public int val;public Node next;public Node(int val) {this.val = val;}}public static Node getIntersectNode(Node head1, Node head2) {if (head1 == null || head2 == null) {return null;}Node loop1 = getLoopNode(head1);Node loop2 = getLoopNode(head2);if (loop1 == null && loop2 == null) {return noLoop(head1, head2);}if (loop1 != null && loop2 != null) {return bothLoop(head1, loop1, head2, loop2);}return null;}private static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {Node cur1 = head1;Node cur2 = head2;if (loop1 == loop2) {int n = 0;while (cur1.next != null) {n++;cur1 = cur1.next;}while (cur2.next != null) {n--;cur2 = cur2.next;}cur1 = n > 0 ? head1 : head2;cur2 = cur1 == head1 ? head2 : head1;n = Math.abs(n);while (n != 0) {n--;cur1 = cur1.next;}while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;}else {cur1 = loop1.next;while (cur1 != loop1) {if (cur1 == loop2) {return loop2;}cur1 = cur1.next;}return null;}}private static Node noLoop(Node head1, Node head2) {Node cur1 = head1;Node cur2 = head2;int n = 0;while (cur1.next != null) {n++;cur1 = cur2.next;}while (cur2.next != null) {n--;cur2 = cur2.next;}if (cur1 != cur2) {return null;}cur1 = n < 0 ? head2 : head1;cur2 = cur1 == head2 ? head1 : head2;n = Math.abs(n);while (n != 0) {n--;cur1 = cur1.next;}while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;}private static Node getLoopNode(Node head) {if (head.next == null || head.next.next ==null) {return null;}Node slow = head.next;Node fast = head.next.next;while (fast != slow) {if (fast == null) {return null;}slow = slow.next;fast = fast.next.next;}fast = head;while (fast != slow) {fast = fast.next;slow = slow.next;}return fast;}public static void main(String[] args) {Node head = new Node(0);head.next = new Node(1);head.next.next = new Node(2);head.next.next.next = new Node(3);head.next.next.next.next = new Node(4);head.next.next.next.next.next = head.next.next;Node head1 = new Node(0);head1.next = new Node(1);head1.next.next = new Node(2);head1.next.next.next = new Node(3);head1.next.next.next.next = new Node(4);head1.next.next.next.next.next = head.next.next.next;Node intersectNode = getIntersectNode(head, head1);System.out.println(intersectNode.val);}
}

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

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

相关文章

leetcode刷题详解五

117. 填充每个节点的下一个右侧节点指针 II 关键点&#xff1a;先递归右子树 画一下就知道了&#xff0c;画一个四层的二叉树&#xff0c;然后右子树多画几个节点就知道为啥了 Node* connect(Node* root) {if(!root || (!root->left && !root->right)){return ro…

实战oj题——括号匹配问题

前言&#xff1a;前面我们已经做了一些关于顺序表和链表的oj题&#xff0c;今天我们就来解决一些有关于栈和队列的oj题。 我们对这个题看起来毫无头绪&#xff0c;但是我们刚学习了栈&#xff0c;就可以用栈来解决这一类问题&#xff0c;如果我们读取到左括号就入栈&#xff0c…

2023年最新Visual Studio下载安装以及C语言环境搭建教程(含C语言入门教程)

文章目录 写在前面C语言简介Visual Studio简介Visual Studio安装教程 C语言入门Visual Studio使用教程 写在后面 写在前面 2023年最新Visual Studio下载安装以及C语言环境搭建教程来啦&#xff01;一起来看看吧~ C语言简介 C语言是一种高级编程语言&#xff0c;由美国贝尔实…

90. 打家劫舍II (房子围成一圈)

题目 题解 class Solution:def rob(self, nums: List[int]) -> int:def dp(nums: List[int]) -> int:N len(nums)# 定义状态&#xff1a;dp[i]表示从第i个房屋开始偷窃&#xff0c;能够偷到的最高金额dp [0 for i in range(N)]for i in range(N-1, -1, -1):if i N-1:…

uiautomator2 无法连接 ATX-Agent

最近需要写个安卓自动项目&#xff0c;本身不想用appium 。主要是appium需要安装的依赖太多&#xff0c;一单换个环境又要配置新的环境。但是ATX-Agent装好之后怎么都连接不是。 报错信息如下&#xff1a; .........省略............ uiautomator2.exceptions.GatewayError: (…

渗透测试【一】:渗透测试常见问题

渗透测试【一】&#xff1a;渗透测试常见问题 1、问题清单2、问题现象及解决办法2.1、点击劫持2.2、用户枚举2.3、Springboot未授权访问2.4、Swagger未授权访问2.5、Host头注入2.6、任意文件上传2.7、敏感路径泄露2.8、跨域资源共享2.9、Spring Cloud Gateway RCE2.10、Content…

【挑战业余一周拿证】CSDN官方课程目录

一、亚马逊云科技简介 二、在云中计算 三、全球基础设施和可靠性 四、联网 五、存储和数据库 六、安全性 七、监控和分析 八、定价和支持 九、迁移和创新 十、云之旅 关注订阅号 CSDN 官方中文视频&#xff08;免费&#xff09;&#xff1a;点击进入 一、亚马逊云科…

女生儿童房装修:原木上下铺搭配粉色调。福州中宅装饰,福州装修

你是否正在为女生儿童房的装修而发愁呢&#xff1f;该如何让房间既适合孩子生活&#xff0c;又能够满足日常学习的需要呢&#xff1f;这里有一个精美的装修案例&#xff0c;或许能够为你提供一些灵感。 1️⃣ 原木上下铺 房间的上下铺采用了原木色调&#xff0c;带来了自然、温…

STM32 F1 串口空闲中断 + DMA实现数据发送

DMA实现数据发送 文章目录 DMA实现数据发送前言一、DMA二、代码编写1.DMA2.USART3.main 前言 当你遇到通信数据量大的时候&#xff0c;可以使用 空闲中断 DMA 的方案来减轻 CPU 的压力。 或者 在进行stm32开发时&#xff0c;有时会遇到这种情况&#xff1a;需要在设备间进行数…

1.1 C语言之入门:使用Visual Studio Community 2022运行hello world

1.1 使用Visual Studio Community 2022运行c语言的hello world 一、下载安装Visual Studio Community 2022 与 新建项目二、编写c helloworld三、编译、链接、运行 c helloworld1. 问题记录&#xff1a;无法打开源文件"stdio.h"2. 问题记录&#xff1a;调试和执行按钮…

【Linux】bash 终端指令

进程 $ ps aux | grep pwd work 63317 0.0 0.0 51192 612 pts/9 S 14:22 0:00 grep /home/work/search/1000000.dyenv-user-diaoyan-baiseCliPlus-baisePlus-195522.diaoyan.yq/ala-ac/output_root端口 查看本机端口开放情况 netstat -tln | grep :31 tcp …

Unsupervised Skill Discovery via Recurrent Skill Training论文笔记

Zheyuan Jiang, Jingyue Gao, Jianyu Chen (2022). Unsupervised Skill Discovery via Recurrent Skill Training. In Conference on Neural Information Processing Systems (NeurIPS), 2022. 通过循环技能训练发现无监督技能 1、Motivation 以往的无监督技能发现方法主要使…

可燃气体监测仪助力燃气管网安全监测,效果一览

城市地下管线是指城市范围内供应水、排放水、燃气等各类管线及其附属设施&#xff0c;它们是保障城市正常运转的重要基础设施且影响着城市生命线。其中燃气引发的事故近些年不断增加&#xff0c;由于燃气管线深埋地下环境复杂&#xff0c;所以仅仅依赖人工巡查难以全面有效地防…

17. Python 数据库操作之MySQL和SQLite实例

目录 1. 简介2. 使用PyMySQL2. 使用SQLite 1. 简介 数据库种类繁多&#xff0c;每种数据库的对外接口实现各不相同&#xff0c;为了方便对数据库进行统一的操作&#xff0c;大部分编程语言都提供了标准化的数据库接口&#xff0c;用户不需要了解每种数据的接口实现细节&#x…

【每日一题】1457. 二叉树中的伪回文路径-2023.11.25

题目&#xff1a; 1457. 二叉树中的伪回文路径 给你一棵二叉树&#xff0c;每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的&#xff0c;当它满足&#xff1a;路径经过的所有节点值的排列中&#xff0c;存在一个回文序列。 请你返回从根到叶子节点的所有路…

Re55:读论文 Entities as Experts: Sparse Memory Access with Entity Supervision

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Entities as Experts: Sparse Memory Access with Entity Supervision 模型名称&#xff1a;Entities as Experts (EaE) ArXiv网址&#xff1a;https://arxiv.org/abs/2004.07202 本文…

人工智能基础_机器学习050_对比sigmoid函数和softmax函数的区别_两种分类器算法的区别---人工智能工作笔记0090

可以看到最上面是softmax的函数对吧,但是如果当k = 2 那么这个时候softmax的函数就可以退化为sigmoid函数,也就是 逻辑斯蒂回归了对吧 我们来看一下推导过程,可以看到上面是softmax的函数 可以看到k=2 表示,只有两个类别对吧,两个类别的分类不就是sigmoid函数嘛对吧,所以说 …

ubuntu 安装 jetbrains-toolbox

ubuntu 安装 jetbrains-toolbox 官网下载 jetbrains-toolbox jetbrains 官网 jetbrains 官网&#xff1a;https://www.jetbrains.com/ jetbrains-toolbox 官网下载页面 在下载页面点击 Download 安装 jetbrains-toolbox 解压 jetbrains-toolbox 安装包 到指定目录 本案例将…

STM32 默认时钟更改 +debug调试

STM32时钟 文章目录 STM32时钟前言一、修改系统时钟二、DEBUG 前言 为什么我们要改STM32的时钟呢&#xff0c;打个比方在做SPI驱动的时候&#xff0c;需要16M的时钟&#xff0c;但是stm32默认是72的分频分不出来&#xff0c;这个时候我们就要改系统时钟了&#xff0c;那么怎么…

[科普] 无刷直流电机驱动控制原理图解

Title: [科普] 无刷直流电机驱动控制原理图解 文章目录 I. 引言II. 直流电机的原理1. 有刷直流电机和无刷直流电机的区别2. 有刷直流电机的运行原理3. 既是电动机又是发电机 III. 无刷直流电机的原理1. 无刷直流电机与永磁同步电机的区别2. 无刷直流电机的换向控制原理3. 无刷直…