1.寻找两个链表的第一个公共结//这道题可以有很多种思路, 我们按照, 有坏到好的顺序, 来依次介绍每种思路。 同时, 这种顺序, 也是我们面对这道题时,能想到的 由易到难的思路
第一种思路:蛮力法: 简单粗暴, 蛮力法。 假设有两个链表 L1 与 L2. 我们拿出 L1 的第一个结点, 在 L2 中依次遍历一遍, 遇到数值相同结点, 则返回。 否则 , 拿出 L1 中第二个结点, 重复上述过程, 第一个返回的结点 即为两个链表的 第一个公共结点。
第一种思路的时间复杂度 为 O( m*n ), 空间复杂度 O( 1 ) 假设第一个链表长度为m, 第二个链表长度为n
第二种思路: 借助外部空间法: 我们先来 研究下 两个链表 有公共结点意味着什么, 意味着 这个公共结点为两个 链表所共有, 又因为(我们题设给出的条件为这个链表为单链表, 且结点中 只有两个数据成员, 一个为 data, 一个为指向下一个结点的指针 next)结点中 只有一个next成员, 所以, 这个公共结点之后, 两个链表的所有节点都是一样的。
即, 如图, 这两个链表, 是倒Y字形交叉, 而不是 倒X形状交叉. 所以我们可以 这样解题, 从链表的尾部开始遍历, 一直往前, 遇到的最后一个数据相同的结点 , 即是我们要找的结点。 可是这是单链表, 我们没有指向 prev 的指针, 如何从最后一个结点往前遍历呢?
这时我们就要用到栈这种数据结构, 将两个链表, 分别入 栈s1 和 s2. 入栈结束后, s1 和 s2栈顶相同。 我们 pop 栈s1 和 s2. pop到最后一个相等的结点, 即是我们要找的结点
第二种思路 时间复杂度 O( m+n ), 空间复杂度 O( m+n )
第三种思路:不借助外部空间法: 我们再想, 两个链表 L1 和 L2 , 如果 L1 长度 为 7 ,L2长度为 5. 则, L1 和 L2的公共结点一定在 后五个结点当中。 因为他们从公共结点往后的结点是相同的, 所以 公共结点不可能出现在 L1 的前两个结点中。
所以我们就可以, 先遍历一遍 L1 与 L2 得到他们的长度。 假如L1 为 7 . L2 为 5. 则让 L1先遍历两个结点, 接着开始同时遍历 L1 和 L2. 当它们遇到第一个数据相等的结点, 就是我们要找的 结点。
第三种思路: 时间复杂度 O( m+n ), 空间复杂度 O( 1 )
和第二种思路相比, 第三种思路, 时间复杂度没变, 空间复杂度降低 ,是最优的思路。
第一种思路:蛮力法: 简单粗暴, 蛮力法。 假设有两个链表 L1 与 L2. 我们拿出 L1 的第一个结点, 在 L2 中依次遍历一遍, 遇到数值相同结点, 则返回。 否则 , 拿出 L1 中第二个结点, 重复上述过程, 第一个返回的结点 即为两个链表的 第一个公共结点。
第一种思路的时间复杂度 为 O( m*n ), 空间复杂度 O( 1 ) 假设第一个链表长度为m, 第二个链表长度为n
第二种思路: 借助外部空间法: 我们先来 研究下 两个链表 有公共结点意味着什么, 意味着 这个公共结点为两个 链表所共有, 又因为(我们题设给出的条件为这个链表为单链表, 且结点中 只有两个数据成员, 一个为 data, 一个为指向下一个结点的指针 next)结点中 只有一个next成员, 所以, 这个公共结点之后, 两个链表的所有节点都是一样的。
即, 如图, 这两个链表, 是倒Y字形交叉, 而不是 倒X形状交叉. 所以我们可以 这样解题, 从链表的尾部开始遍历, 一直往前, 遇到的最后一个数据相同的结点 , 即是我们要找的结点。 可是这是单链表, 我们没有指向 prev 的指针, 如何从最后一个结点往前遍历呢?
这时我们就要用到栈这种数据结构, 将两个链表, 分别入 栈s1 和 s2. 入栈结束后, s1 和 s2栈顶相同。 我们 pop 栈s1 和 s2. pop到最后一个相等的结点, 即是我们要找的结点
第二种思路 时间复杂度 O( m+n ), 空间复杂度 O( m+n )
和第一种思路相比, 时间复杂度降低, 空间复杂度上升, 相当于用 空间换时间
第三种思路:不借助外部空间法: 我们再想, 两个链表 L1 和 L2 , 如果 L1 长度 为 7 ,L2长度为 5. 则, L1 和 L2的公共结点一定在 后五个结点当中。 因为他们从公共结点往后的结点是相同的, 所以 公共结点不可能出现在 L1 的前两个结点中。
所以我们就可以, 先遍历一遍 L1 与 L2 得到他们的长度。 假如L1 为 7 . L2 为 5. 则让 L1先遍历两个结点, 接着开始同时遍历 L1 和 L2. 当它们遇到第一个数据相等的结点, 就是我们要找的 结点。
第三种思路: 时间复杂度 O( m+n ), 空间复杂度 O( 1 )
和第二种思路相比, 第三种思路, 时间复杂度没变, 空间复杂度降低 ,是最优的思路。
我们只实现第三种思路, 第二种思路的 另一种实现, 可以参见我写的 博客 树的最近公共祖先2, 使用了第二种思路
:
先给出函数的实现代码,晚上用 c++ 再写遍单链表后, 我们再通过各种测试用例 来 测试我们函数的 健壮性.