链表经典面试题

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: (…

Zookeeper(一):在WSL单机搭建Zookeeper伪集群

目录 Zookeeper1 启动单个Zookeeper实例1.1 下载Zookeeper安装包并解压1.2 添加环境变量1.3 修改默认配置1.4 新建数据存储目录和日志目录1.5 启动Zookeeper1.6 停止Zookeeper 2 搭建Zookeeper集群2.1 新建集群目录2.2 配置环境变量2.3 创建节点目录2.4 修改配置2.5 创建节点ID…

2311skia,05绘制文本

绘画文字 绘画文字主要包括转换编码(主要是中文),解析字形(点线或image)和实际渲染三个步骤.在该过程中,解析字形和实际渲染均是耗时步骤. Skia缓存解析文字的结果.在中文字较多,使用多种字体,绘画风格(粗/斜体)有变化时,该缓存会很大,因此Skia文字,限制了缓存的内存. 1,SkP…

CSIT883系统分析与项目管理——Lecture4重点概念

文章目录 一、前言二、重点概念三、题目分析总结一、前言 这次课程给大家介绍信息收集、建模和工作流与项目范围管理相关的知识与题目。同时这节课还有一个重点内容——活动图,我打算单独写一篇文章进行讲解,感兴趣的同学可以留意一下哦! 二、重点概念 1.工作分解结构(W…

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

渗透测试【一】&#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…

某省交控高速公路分公司高效运维

客户背景与挑战 某省交通控股集团下面有一个高速公路分公司&#xff0c;负责运营和管理该省的高速公路网络。随着IT设备的增加和机房动环设备数量的增长&#xff0c;该公司在跨区域跨网络管理、平台升级和扩容方面遇到了挑战。为了解决这些问题&#xff0c;该公司选择使用监控易…

【挑战业余一周拿证】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;调试和执行按钮…

Java入门基础:浅显易懂 do...while

文章目录 前言一、布尔表达式二、do...while三、语法四、示例 前言 do…while 在开发过程中其实并不常用&#xff0c;95%以上都是用 for 而不是 do…while。因为 do…while 能做的 for 能做&#xff0c;do…while 不能做的 for 也能做。所以对于 do…while 能够看懂代码即可 在…

【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 以往的无监督技能发现方法主要使…

Unity优化——脚本优化策略2

大家好&#xff0c;这里是七七&#xff0c;今天继续来介绍几个Unity脚本优化策略 一、更快的GameObject空引用检查 事实证明&#xff0c;对GameObject执行空引用检查会导致一些不必要的开销。与典型的C#对象相比&#xff0c;GameObject和MonoBehaviour是特殊对象&#xff0c;…

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

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

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

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