今天学习一下链表的公共子节点问题
如图所示,有两个链表在某处开始公用子节点,我们的目标是找出开始公用的节点即图片的C1点
1.哈希集合
看到题目的第一个解题思路应当是最容易想到使用hash,遍历第一个链表存到集合中,然后遍历第二个链表并判断当前元素是否存在于集合中,如果存在则保存这个元素退出遍历
代码实现:
public StudentNode getFirstCommonNode(StudentNode headA,StudentNode headB){
Set<StudentNode> set = new HashSet<>();
//遍历headA链表到set集合中
while (headA!=null){
set.add(headA);
headA = headA.next;
}
while (headB!=null){
//判断headB节点是否属于set
if (set.contains(headB)){
return headB;
}
headB=headB.next;
}
return null;
}
2.使用栈
public StudentNode getFirstCommonNode(StudentNode headA,StudentNode headB){
//初始化两个栈
Stack<StudentNode> stackA = new Stack<>();
Stack<StudentNode> stackB = new Stack<>();
//将两个链表压入栈中
while (headA!=null){
stackA.push(headA);
headA = headA.next;
}
while (headB!=null){
stackB.push(headB);
headB = headB.next;
}
StudentNode currentNode = null;
StudentNode popA;
StudentNode popB;
while(stackA.size()>0&&stackB.size()>0){
popA = stackA.pop();
popB = stackB.pop();
//取出的节点相等时就赋值给目标节点,直到取出最后一个相等的节点
if (popA==popB){
currentNode = popA;
}else {
break;
}
}
return currentNode;
}
3.拼接字符串
在遍历完headA链表时指向headB的头结点,遍历完headB时指向headA头结点,核心思想是保持两个链表的长度相等,这样遍历如果有公共子节点就会出现在两个链表的相同index上。
public StudentNode getFirstCommonNode(StudentNode headA, StudentNode headB) {
if (headA == null || headB == null) {
return null;
}
StudentNode currentNodeA = headA;
StudentNode currentNodeB = headB;
while (currentNodeA != currentNodeB) {
currentNodeA = currentNodeA.next;
currentNodeB = currentNodeB.next;
在同时到达末尾时null==null,离开循环,不然如果没有公用节点的话会陷入死循环
if (currentNodeA != currentNodeB) {
//headA到末尾时指向headB头结点
if (currentNodeA == null) {
currentNodeA = headB;
}
//headB到末尾时指向headA头结点
if (currentNodeB == null) {
currentNodeB = headA;
}
}
}
return currentNodeA;
}
4.差和双指针
假设两个链表长度不相同,我们让长度长的那条先遍历,直到剩下长度和另外一条链表长度相等,这样也是保持同时遍历的链表长度相等。
public StudentNode getFirstCommonNode(StudentNode headA, StudentNode headB) {
if (headA==null||headB==null){
return null;
}
StudentNode startNode;
StudentNode endNode;
long diff;
StudentNode headABack = headA;
StudentNode headBBack = headB;
long sizeA = 0;
long sizeB = 0;
//headA链表长度
while (headABack!=null){
headABack=headABack.next;
sizeA++;
}
//headB链表长度
while (headBBack!=null){
headBBack=headBBack.next;
sizeB++;
}
//判断从哪个链表开始遍历
if (sizeA>sizeB){
startNode=headA;
endNode = headB;
diff=sizeA-sizeB;
}else {
startNode = headB;
endNode = headA;
diff=sizeB-sizeA;
}
//长度不相等时
if (diff>0){
for (int i = 1; i <=diff ; i++) {
startNode=startNode.next;
}
}
while (startNode!=endNode ){
startNode=startNode.next;
endNode=endNode.next;
}
return startNode;
}
总结:
以上就是解决两个链表相同节点问题的四个解决方式
就像骨头哥讲的那样,我们遇到问题时首先要仔细的想一遍常用的数据结构和算法思想,或许是我们解决问题的第一步!!
常用的数据结构有数组、链表、队、栈、Hash、集合、树、堆。常用的算法思想有查找、排序、双指针、递归、迭代、分治、贪心、回溯和动态规划等等。