剑指offer题目系列三(链表相关题目)

本篇延续上一篇剑指offer题目系列二,介绍《剑指offer》第二版中的四个题目:O(1)时间内删除链表结点、链表中倒数第k个结点、反转链表、合并两个排序的链表。同样,这些题目并非严格按照书中的顺序展示的,而是按自己学习的顺序,每个题目包含了分析和代码。

9、O(1)时间内删除链表结点

题目:

在O(1)时间内删除链表结点。给定单链表的头指针和一个结点指针,定义一个方法在O(1)时间内删除该结点。

单链表的定义如下:

解答:

单向链表删除一个结点,最直观的想法是从链表的头结点开始顺序遍历查找要删除的结点,然后删除该结点,这种做法的时间复杂度为O(n),显然不满足本题要求。如果我们把下一个结点的信息复制到要删除的结点上,覆盖原有内容,再把下一个结点删除,这样就相当于把该结点删除了,本题解法基于这种方式。

首先把要删除的结点(i)的下一个结点(j)的信息复制到结点i,然后把i指向它的下下个结点(即j的下一个结点),然后再把结点j删除,这样就把i删除了。有两个特殊情况:如果要删除的结点i所在的链表中只有一个结点,那么将其置空(null)即可;如果要删除的结点i是链表尾部的最后一个结点,这就需要从链表的头结点开始,顺序遍历链表到该结点,然后将其置空(null),完成删除。

代码:

可以看到,删除头结点和中间结点的时间复杂度为O(1),而删除尾结点的时间复杂度为O(n),但总的平均时间复杂度还是O(1),符合要求。

10、链表中倒数第k个结点

题目:

输入一个链表,输出该链表中倒数第k个结点。按大多数人的习惯,设链表的尾结点为倒数第一个结点。

单链表的定义如下:

解答:

本题采用快慢指针的思想,可以定义两个指针。第一个指针从链表的头结点开始遍历k-1个结点,第二个指针保持不动;当第一个结点遍历到第k个结点时,第二个结点从链表的头结点开始遍历,两个指针的距离始终保持k-1。当第一个指针遍历到链表的尾结点时,此时第二个指针所在的位置正是倒数第k个结点的位置。需要注意的是链表不能为空(null),同时k不能大于链表长度。

代码:

11、反转链表

题目:

定义一个方法,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

单链表的定义如下:

解答:

本题需要知道三个结点,即当前结点(node)、当前结点的前一个结点(preNode)、当前结点的下一个结点(nextNode)。

反转时,将当前结点(node)的下一个结点指向其前一个结点(preNode),这样当前结点(node)与其原来的下一个结点(nextNode)之间发生了断裂,所以需要保存其原来的下一个结点(nextNode)信息。然后将当前结点赋值给前一个结点(preNode),下一个结点赋值给当前结点……以此类推,直到下一个结点为空,此时当前结点就是反转后链表的头结点。

代码:

12、合并两个排序的链表

题目:

输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是递增排序的。

例如:输入链表1:1->3->5->7

链表2:2->4->6->8

返回链表:1->2->3->4->5->6->7->8

单链表的定义如下:

解答:

本题采用递归方法,利用归并的思想。

首先定义一个新链表(newList),存放合并后的数据。然后分别遍历两个链表(list1和list2)的头结点,比较其大小。如果list1的头结点小于等于list2的头结点,则将list1的头结点添加到新链表中(newList),然后将list1头结点的下一个结点与list2的头结点作为参数,执行本方法(即递归);反过来如果list1的头结点大于list2的头结点,则将list2的头结点添加到新链表中(newList),然后将list1的头结点与list2头结点的下一个结点作为参数,执行本方法(即递归)……以此类推,不断递归,直到list1或list2为空,然后将另一个列表剩余结点直接放到新链表中即可。

例如题目中两个链表第一次比较时,list1的头结点1小于list2的头结点2,故list1头结点1放入newList中;然后list1头结点的下一个结点3大于list2的头结点2,故list2头结点2放入newList中;然后list1头结点的下一个结点3小于list2头结点的下一个结点4,故list1头结点的下一个结点3放入newList中……

代码:

转载请注明出处 http://www.cnblogs.com/Y-oung/p/8933438.html

工作、学习、交流或有任何疑问,请联系邮箱:[email protected]  微信:yy1340128046

原文地址:https://www.cnblogs.com/Y-oung/p/8933438.html

时间: 2024-10-05 23:48:14

剑指offer题目系列三(链表相关题目)的相关文章

剑指Offer对答如流系列 - 复杂链表的复制

面试题35:复杂链表的复制 题目描述 请实现函数ComplexListNode Clone(ComplexListNode pHead),复制一个复杂链表.在复杂链表中,每个节点除了有一个next引用向下一个节点外,还有一个sibling 指向链表中的任意节点或者null. 节点的定义如下: public class ComplexListNode { int val; ComplexListNode next = null; ComplexListNode sibling = null; Co

剑指Offer对答如流系列 - 反转链表

面试题24:反转链表 题目描述 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点 链表结构 public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } } 问题分析 头插法是反转链表非常经典的一种手段,这里演示一下吧,毕竟这个在JDK源码中也能遇见. 核心代码如下: ListNode Inverse(ListNode L) { ListNode p,

剑指Offer对答如流系列 - 从上往下打印二叉树

面试题32:从上往下打印二叉树 题目描述 树的结构定义如下: public class Node{ int e; Node left; Node right; Node(int x) { e = x; } } (一)不分行从上到下打印二叉树 从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印. 比如下面二叉树,输出顺序为 8 6 10 5 7 9 11 (二)分行从上到下打印二叉树 从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行. 比如下面二叉树,输出

剑指OFFER之合并有序链表(九度OJ1519)

题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则.(hint: 请务必使用链表.) 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为两个整数n和m(0<=n<=1000, 0<=m<=1000):n代表将要输入的第一个链表的元素的个数,m代表将要输入的第二个链表的元素的个数.下面一行包括n个数t(1<=t<=1000000):代表链表一中的元素.接下来一行包含m个元素,s(1<

剑指Offer对答如流系列 - 数组中数字出现的次数

面试题56:数组中数字出现的次数 题目描述 问题(1)数组中只出现一次的两个数字 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). 问题(2)数组中唯一只出现一次的数字 在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次.请找出那个只出现一次的数字. 问题分析 问题(1)分析 在这篇文章剑指Offer对答如流系列 - 二进制中 1 的个数中,我们详细探讨了位运算,其中有重要的一条:两个相同的数异

剑指offer (37) 两个链表的第一个公共结点

题目:输入两个链表,找出它们的第一个公共结点 如果两个链表有公共结点,那么公共结点一定出现在两个链表的尾部 如果两链表长度不相等,那么达到公共结点的步数就不一致,如何确保 两个链表从头开始遍历,同步达到公共结点? 这是关键所在 如果两链表长度相同,那么就可以同步达到了? 由此,我们就需要 让两个链表长度"相等" 我们假设 两链表长度分别为m和n,且m > n, 那么我们可以在较长链表中 先走 m - n 步,然后 两个链表游标同步走,如果有公共结点,那么就一定同时达到 ListN

【剑指offer】两个链表的第一个公共结点

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26097395 简单题,剑指offer上的第37题,九度OJ上AC. 题目描述: 输入两个链表,找出它们的第一个公共结点. 输入: 输入可能包含多个测试样例.对于每个测试案例,输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的两个链表的元素的个数.接下来的两行,第一行为第一个链表的所有元素,中间用空格隔开.第二行为第二个链表的所有元素,中间用空格隔开. 输出: 对应

剑指Offer对答如流系列 - 礼物的最大价值

面试题47:礼物的最大价值 题目描述 在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0).你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格直到到达棋盘的右下角.给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物? 比如下面的棋盘中,如果按照红色数字的路线走可以拿到最大价值为53的礼物 问题分析 动态规划:定义f(i,j)为到达(i,j)位置格子时能拿到的礼物总和的最大值,则有:f(i,j)=max{f(i-1,j),f(i,j-1)}+va

剑指Offer对答如流系列 - 序列化二叉树

面试题37:序列化二叉树 题目描述 请实现两个函数,分别用来序列化和反序列化二叉树. 树的结构定义如下: public class Node { int val = 0; Node left = null; Node right = null; public Node(int val) { this.val = val; } } 问题分析 一般情况下,需要采用前/后序遍历和中序遍历才能确定一个二叉树,具体的内容我们之前探讨过 剑指Offer对答如流系列 - 重建二叉树 但是采用这种方式进行序列化

剑指Offer对答如流系列 - 把数组排成最小的数

面试题45:把数组排成最小的数 题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3, 32, 321},则打印出这3个数字能排成的最小数字321323. 问题分析 之前我们做过字符全排列的习题 剑指Offer对答如流系列 - 字符串的排列,但是将算法思想应用到这一题的话,效果不好,求出所有的组合,再计算出组合的最小值,这效率该多低啊. 我们还要进一步探究,看看有没有不错的规律,供我们使用. 因为数字拼接后的长度一样,拼接后的结果