leetcode No160 相交链表 java
Posted 短腿Cat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode No160 相交链表 java相关的知识,希望对你有一定的参考价值。
题目
来源:力扣(LeetCode)
链接:leetcode No160 相交链表
分析
题目给定两条链表,我们需要找到这两条链表开始相交的那个节点,题意非常好理解,那么还是有几个要注意的点:
- 题目要求的是节点要相同,而不是节点的数值相同,因此示例1中的两个‘1’节点就不是相同的节点
- 比较的时候比的是节点对象的值,而不是节点val值
今天的每日一题是一道简单题,既然是一道简单题,那么我们就应该尝试着从多个角度解决它以达到我们训练能力的目的,下面我来说说这一道题的多种解法。
这里我们先给定题目链表的结构:
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
1、普通暴力解法(1390ms)
暴力解法的思路非常简单,假设两条链表a 和 b,我们对a的每一个节点循环一遍b的节点,看是否为相等节点(相同节点),注意不是val值相等,而是对象值相等。因此,简简单单的两层循环就能搞定,时间复杂度O(n2),空间复杂度O(1).
//朴素解法(1390ms)
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
for (ListNode a = headA; a != null; a = a.next) {
for (ListNode b = headB; b != null; b = b.next) {
if (a.equals(b))
return a;
}
}
return null;
}
}
实际提交结果的运行实际1390ms,可以说是惨目忍睹
2、哈希表比较法(8ms)
这个方法思路和第一个暴力法没啥区别,只是我们不是暴力枚举,而是通过:将链表a的所有节点放入表中,然后通过枚举b的节点是否有在a中有相等节点(对象值相等!),有则马上返回,无则循环完之后返回null
//哈希表写法(8ms)
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set = new HashSet<>();
//将headA的所有节点全部放入表中
while (headA != null) {
set.add(headA);
headA = headA.next;
}
//枚举headB中是否有相等节点,有则马上返回,无则循环完之后返回null
while (headB != null) {
if (set.contains(headB))
return headB;
else
headB = headB.next;
}
return null;
}
}
3、堆栈写法(4ms)
若两个链表有相交,则相交之后的部分全都是相等的,也就是说链表的尾部分一定有一段是相等的,但是我们使用的是单链表,不可以从后往前操作,因此我们利用一个工具—堆栈,先将两个链表 a,b 的节点分别全部入栈stack_a和stack_b:
然后两个栈一个一个弹出比较,如果是相等的则该处为重合部分,继续弹出,直到有不相等的部分,则前一个弹出的节点就是刚好相交的节点:
代码如下:
//堆栈写法(4ms)
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Deque<ListNode> a = new ArrayDeque<>();
Deque<ListNode> b = new ArrayDeque<>();
//将headA链全部压入a
for (ListNode i = headA; i != null; i = i.next)
a.addLast(i);
//将headB链全部压入b
for (ListNode i = headB; i != null; i = i.next)
b.addLast(i);
ListNode result = null;
//a和b都不为空 且 a的栈顶对象和b的栈顶对象相等时可以循环弹出
while (!(a.isEmpty() || b.isEmpty()) && a.peekLast().equals(b.peekLast())) {
result = a.pollLast();
b.pollLast();
}
return result;
}
}
4、双指针解法(1ms)
这个解法是速度比较快的一种解法,优于前几种,下面说说思路:
因为从相交部分开始往后一直都是一样的节点,我们让两个指针i,j分别在a链和b链上以一定的相对位置一起往后移动(每次移动一格),这样的相对位置能使i和j同时到达他们所在的链表的尾部(大前提是有相交的节点,否则返回的是null)
上图的i、j指针同时往后移动则可以同时到达尾部,i和j的相对位置的差值为1(因为i在第一个,j在第二个,2-1 = 1)
那么这个相对差值怎么计算呢,其实非常简单,就是两链表长度的差值,一开始先让i,j都在链表的首位置,让更长的那个链表的指针先移动这个差值单位,然后一起往后移动,直到出现i、j所指的节点相等时,则该节点就是相交节点了。
如下是实现代码:
//双指针写法(1ms)
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int len1 = 0, len2 = 0;
ListNode a = headA, b = headB;
//计算headA链长度
while (a != null) {
len1++;
a = a.next;
}
//计算headB链长度
while (b != null) {
len2++;
b = b.next;
}
//计算差值
int w = Math.abs(len1 - len2);
//初始化指针位置
while (w-- > 0 && headA != null && headB != null) {
if (len1 > len2)
headA = headA.next;
else
headB = headB.next;
}
//开始移动,遇见相等的节点则返回节点,
while (headA != null && headB != null) {
if (headA.equals(headB))
return headA;
else {
headA = headA.next;
headB = headB.next;
}
}
return null;
}
}
总结
以上就是我所总结的该题的所有解法了,一共四个:
1、暴力
2、堆栈
3、哈希
4、双指针
从最暴力的1390ms 优化到 1ms , 虽然题目很简单,但是当你自己能一步一步优化过来的时候,心里会很有成就感的。
希望喜欢的看客们留下你的赞,谢谢嗷~
以上是关于leetcode No160 相交链表 java的主要内容,如果未能解决你的问题,请参考以下文章