目录
题目四 将单向链表按某值划分成左边小、中间相等、右边大的形式
哈希表的简单介绍
(1)对于java中的哈希函数有HashSet和HashMap,其中HashSet函数是只有key,不带有伴随数据value,而HashMap是带有伴随数据value的,结构组织上没有区别,唯一区别就是有没有value代码展示区别如下:
// hashSet1的key是基础类型->int类型
HashSet<Integer> hashSet1 = new HashSet<>();//只有key没有value
hashSet1.add(3);//加入一个值
System.out.println(hashSet1.contains(3));//查看这个值是否存在
hashSet1.remove(3);//移去一个值
System.out.println(hashSet1.contains(3));//查看这个值是否存在
// hashMap1的key是基础类型->String类型
HashMap<String, Integer> hashMap1 = new HashMap<>();//同时有key和value
String str1 = "key";
String str2 = "key";
hashMap1.put(str1, 1);//加入,str1为key,1为value
System.out.println(hashMap1.containsKey(str1));//查询某个key是否存在
System.out.println(hashMap1.containsKey(str2));
System.out.println(hashMap1.get(str1));//拿出某个key
System.out.println(hashMap1.get(str2));
hashMap1.put(str2, 2);
System.out.println(hashMap1.containsKey(str1));
System.out.println(hashMap1.containsKey(str2));
System.out.println(hashMap1.get(str1));
System.out.println(hashMap1.get(str2));
hashMap1.remove(str1);//删除某个key
System.out.println(hashMap1.containsKey(str1));
System.out.println(hashMap1.containsKey(str2));
对于上述哈希表中增删改查的操作,无论数据量多大,时间复杂度都是常数级别的,但是常数比较大。
(2)放入哈希表的东西,如果是基础类型,内部按值传递,内存占用就是这个东西的大小,因为会在哈希表中拷贝一份;如果不是基础类型,内部按引用传递,内存占用就是这个东西内存地址的大小,一律为八字节。
有序表的简单介绍
(1)对于java中的表示有序表函数有TreeSet和TreeMap,其中TreeSet函数是只有key,不带有伴随数据value,而TreeMap是带有伴随数据value的,结构组织上没有区别,唯一区别就是有没有value。代码展示区别如下:
// treeSet的key是非基础类型->Node类型
TreeSet<Node> treeSet = new TreeSet<>();
nodeA = new Node(5);
nodeB = new Node(3);
nodeC = new Node(7);
TreeMap<Integer, String> treeMap1 = new TreeMap<>();
treeMap1.put(7, "我是7");
treeMap1.put(5, "我是5");
treeMap1.put(4, "我是4");
treeMap1.put(3, "我是3");
treeMap1.put(9, "我是9");
treeMap1.put(2, "我是2");
//以下是有序表的一些固定操作
System.out.println(treeMap1.containsKey(5));
System.out.println(treeMap1.get(5));
System.out.println(treeMap1.firstKey() + ", 我最小");
System.out.println(treeMap1.lastKey() + ", 我最大");
System.out.println(treeMap1.floorKey(8) + ", 在表中所有<=8的数中,我离8最近");
System.out.println(treeMap1.ceilingKey(8) + ", 在表中所有>=8的数中,我离8最近");
System.out.println(treeMap1.floorKey(7) + ", 在表中所有<=7的数中,我离7最近");
System.out.println(treeMap1.ceilingKey(7) + ", 在表中所有>=7的数中,我离7最近");
treeMap1.remove(5);
System.out.println(treeMap1.get(5) + ", 删了就没有了哦");
它和哈希表的区别就是哈希表内部是无序组织key的,而有序表内部是有序组织key的,所以有很多哈希表没有的功能,上面代码就可以看出。性能上比哈希表差,有序表增删改查的操作时间复杂度都是。
(2)红黑树、AVL数、size-balance-tree和跳表等都属于有序表结构,只是底层具体实现不同。
(3)放入有序表的东西,如果是基础类型,內部按值传递,内存占用就是这个东西的大小;如果不是基础类型,必须提供比较器,内部按引用传递,内存占用是这个东西内存地址的大小。
链表
面试时链表解题的方法论:
(1)对于笔试,不用太在乎空间复杂度,一切为了时间复杂度
(2)对于面试,时间复杂度依然放在第一位,但是一定要找到空间复杂度最省的方法
重要技巧:
(1)额外数据结构记录
(2)快慢指针
题目实战
题目一 反转单向和双向链表
分别实现反转单向链表和反转双向链表的函数,要求:如果链表的长度为N,时间复杂度要求为,额外空间复杂度为
。
public class Code02_ReverseList {
public static class Node {//不含头节点,单向链表的建立
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node reverseList(Node head) {//反转单向链表
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static class DoubleNode {//双向链表的建立
public int value;
public DoubleNode last;
public DoubleNode next;
public DoubleNode(int data) {
this.value = data;
}
}
public static DoubleNode reverseList(DoubleNode head) {//反转双向链表
DoubleNode pre = null;
DoubleNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
head.last = next;
pre = head;
head = next;
}
return pre;
}
public static void printLinkedList(Node head) {//打印单向反转链表
System.out.print("Linked List: ");
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
System.out.println();
}
public static void printDoubleLinkedList(DoubleNode head) {//打印双向反转链表
System.out.print("Double Linked List: ");
DoubleNode end = null;
while (head != null) {
System.out.print(head.value + " ");
end = head;
head = head.next;
}
System.out.print("| ");
while (end != null) {
System.out.print(end.value + " ");
end = end.last;
}
System.out.println();
}
public static void main(String[] args) {//主函数
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
printLinkedList(head1);
head1 = reverseList(head1);
printLinkedList(head1);
DoubleNode head2 = new DoubleNode(1);
head2.next = new DoubleNode(2);
head2.next.last = head2;
head2.next.next = new DoubleNode(3);
head2.next.next.last = head2.next;
head2.next.next.next = new DoubleNode(4);
head2.next.next.next.last = head2.next.next;
printDoubleLinkedList(head2);
printDoubleLinkedList(reverseList(head2));
}
}
对于链表这一块的代码,一定要动手画一画就很容易理解。
题目二 打印两个有序链表的公共部分
给定两个有序链表的头指针head1和head2,打印两个链表的公共部分。如果两个链表的长度之和为N,时间复杂度要求为,额外空间复杂度要求为
。
public class Code03_PrintCommonPart {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static void printCommonPart(Node head1, Node head2) {//打印公共部分
System.out.print("Common Part: ");
while (head1 != null && head2 != null) {//当两个链表的头指针都不指向空时
//两个指针指的值比较,谁小谁上面的指针向下移动,相等时打印所指向的值
if (head1.value < head2.value) {
head1 = head1.next;
} else if (head1.value > head2.value) {
head2 = head2.next;
} else {
System.out.print(head1.value + " ");
head1 = head1.next;
head2 = head2.next;
}
}
System.out.println();
}
public static void printLinkedList(Node node) {//打印公共部分
System.out.print("Linked List: ");
while (node != null) {
System.out.print(node.value + " ");
node = node.next;
}
System.out.println();
}
public static void main(String[] args) {//主函数
Node node1 = new Node(2);
node1.next = new Node(3);
node1.next.next = new Node(5);
node1.next.next.next = new Node(6);
Node node2 = new Node(1);
node2.next = new Node(2);
node2.next.next = new Node(5);
node2.next.next.next = new Node(7);
node2.next.next.next.next = new Node(8);
printLinkedList(node1);
printLinkedList(node2);
printCommonPart(node1, node2);
}
}
题目三 判断一个链表是否为回文结构
给定一个单链表的头节点head,请判断该链表是否为回文结构。要求如果链表长度为N,时间复杂度达到,额外空间复杂度达到
。
(1)如果在笔试中遇到,不考虑空间复杂度的情况下,可以直接把这个结构放进栈里,然后依次弹出,同时原结构从前往后比对,如果栈空之前比对都相同,则是回文结构,否则不是。
// 需要n个额外空间
public static boolean isPalindrome1(Node head) {
Stack<Node> stack = new Stack<Node>();
Node cur = head;
while (cur != null) {
stack.push(cur);//依次入栈
cur = cur.next;
}
while (head != null) {
if (head.value != stack.pop().value) {//依次出栈比对
return false;
}
head = head.next;
}
return true;//栈为空之前比对均相同,是回文结构
}
(2)巧妙入栈可以更省空间一些,即对于一个结构,只入栈这个结构的一半,然后出栈比对。要想实现这个操作,需要用到一个技巧,也就是快慢指针,简单理解就是定义两个指针,两个指针的移动速度不同,快指针一次走两步,慢指针一次走一步,快指针走到最后时,慢指针指向结构的中间。
// 只需要n/2的空间
public static boolean isPalindrome2(Node head) {
if (head == null || head.next == null) {
return true;
}//如果头指针为空或者头指针的下一个为空,是回文结构,直接返回true
Node right = head.next;//慢指针
Node cur = head;//快指针
while (cur.next != null && cur.next.next != null) {//当快指针均没有指到最后
right = right.next;//慢指针一次移动一步
cur = cur.next.next;//快指针一次移动两步
}//循环结束,慢指针指向中间位置
Stack<Node> stack = new Stack<Node>();//引入栈
while (right != null) {//当慢指针不为空
stack.push(right);//慢指针所指的元素依次入栈
right = right.next;//慢指针向后移动
}
while (!stack.isEmpty()) {//当栈不为空时
if (head.value != stack.pop().value) {//出栈依次比对
return false;
}
head = head.next;
}
return true;
}
对于其他种类的快慢指针的问题,可以根据需求,让快指针先走几步或者慢指针先走几步,或者其他的操作,根据需要改写。
(3)不使用额外空间来解决这个问题,当面试中遇到这个问题采用此方式解决。
// 不需要额外空间
public static boolean isPalindrome3(Node head) {
if (head == null || head.next == null) {
return true;
}//如果头指针为空或者头指针下一个为空,为回文结构,直接返回
Node n1 = head;
Node n2 = head;
while (n2.next != null && n2.next.next != null) { // 利用快慢指针,找到中间位置
n1 = n1.next; // 慢指针
n2 = n2.next.next; // 快指针
}
//将右半部分的指针反转过来
n2 = n1.next; // n2指向右边部分的第一个节点
n1.next = null;
Node n3 = null;
while (n2 != null) {
n3 = n2.next;
n2.next = n1;
n1 = n2;//n1移动
n2 = n3; //n2移动
}
n3 = n1; // n3指向最后一个节点
n2 = head;// n2指向第一个节点
boolean res = true;
while (n1 != null && n2 != null) { // 当两指针都没有指向空时,检查两个指针所指的元素是否相同
if (n1.value != n2.value) {
res = false;
break;
}
n1 = n1.next; // n1向中间移动
n2 = n2.next; //n2向中间移动
}
n1 = n3.next;
n3.next = null;
while (n1 != null) { // 右半部分的指针方向折过去
n2 = n1.next;
n1.next = n3;
n3 = n1;
n1 = n2;
}
return res;
}
题目四 将单向链表按某值划分成左边小、中间相等、右边大的形式
给定一个单链表的头节点head,节点的值类型是整型,再给定一个整数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于pivot的节点,中间部分都是值等于pivot的节点,右部分都是值大于pivot的节点。
[进阶]在实现原问题功能的基础上增加如下的要求,要求调整后所有小于pivot的节点之间的相对顺序和调整前一样,调整后所有等于pivot的节点之间的相对顺序和调整前一样,调整后所有大于piovt的节点之间的相对顺序和调整前一样。同时时间复杂度达到,额外空间复杂度达到
。
(1)针对原题目的第一种解决方式,在笔试中,不追求空间复杂度最小,直接将单链表的值放进node数组中,利用快速排序中的partition函数将小于pivot的放左边,等于的放中间,大于的放右边。
public static Node listPartition1(Node head, int pivot) {
if (head == null) {
return head;
}//如果头指针指向空,直接返回头指针所指的值
Node cur = head;
int i = 0;
while (cur != null) {
i++;
cur = cur.next;
}//统计单链表的长度
Node[] nodeArr = new Node[i];//定义一个和单链表长度相等的node数组
i = 0;
cur = head;
for (i = 0; i != nodeArr.length; i++) {
nodeArr[i] = cur;
cur = cur.next;
}//将单链表中的值依次放入数组中
arrPartition(nodeArr, pivot);//使用partition函数划分
for (i = 1; i != nodeArr.length; i++) {
nodeArr[i - 1].next = nodeArr[i];
}//将node数组中加上指向箭头方向
nodeArr[i - 1].next = null;
return nodeArr[0];//返回数组第一个node
}
public static void arrPartition(Node[] nodeArr, int pivot) {
int small = -1;
int big = nodeArr.length;
int index = 0;
while (index != big) {
if (nodeArr[index].value < pivot) {
swap(nodeArr, ++small, index++);
} else if (nodeArr[index].value == pivot) {
index++;
} else {
swap(nodeArr, --big, index);
}
}
}
public static void swap(Node[] nodeArr, int a, int b) {
Node tmp = nodeArr[a];
nodeArr[a] = nodeArr[b];
nodeArr[b] = tmp;
}
(2)题目进阶需要划分前后稳定,采用下面的方法实现。关于链表代码的理解多去看,去画,可以很好的理解。
public static Node listPartition2(Node head, int pivot) {
Node sH = null; // small head
Node sT = null; // small tail
Node eH = null; // equal head
Node eT = null; // equal tail
Node bH = null; // big head
Node bT = null; // big tail
Node next = null;
// every node distributed to three lists
while (head != null) {
next = head.next;
head.next = null;
if (head.value < pivot) {
if (sH == null) {
sH = head;
sT = head;
} else {
sT.next = head;
sT = head;
}
} else if (head.value == pivot) {
if (eH == null) {
eH = head;
eT = head;
} else {
eT.next = head;
eT = head;
}
} else {
if (bH == null) {
bH = head;
bT = head;
} else {
bT.next = head;
bT = head;
}
}
head = next;
}
// small and equal reconnect
if (sT != null) {
sT.next = eH;
eT = eT == null ? sT : eT;
}
// all reconnect
if (eT != null) {
eT.next = bH;
}
return sH != null ? sH : eH != null ? eH : bH;
}
题目五 复制含有随机指针节点的链表
一种特殊的单链表节点类型描述如下:
class Node {
int value;
Node next;
Node rand;
Node(int val){
value=val;
}
}
rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点,也可能指向null。给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。要求时间复杂度,额外空间复杂度
。
(1)在笔试中,不考虑使用额外空间时可以使用哈希表进行求解,具体求解代码如下:
public static Node copyListWithRand1(Node head) {
HashMap<Node, Node> map = new HashMap<Node, Node>();
Node cur = head;
while (cur != null) {//通过cur指针进行移动,将旧节点克隆一遍
map.put(cur, new Node(cur.value));
cur = cur.next;
}
cur = head;
while (cur != null) {
//cur老节点
//map.get(cur)新节点
map.get(cur).next = map.get(cur.next);//新节点的下一个连接的是老节点的下一个节点的克隆节点
map.get(cur).rand = map.get(cur.rand);//新节点的rand指针指向的是老节点的rand指针所指的老节点的新节点
cur = cur.next;
}
return map.get(head);//返回克隆链表的头
}
(2)在面试中不使用额外空间的做法,具体代码如下:
public static Node copyListWithRand2(Node head) {
if (head == null) {
return null;
}//如果头指针指向空,直接返回空
Node cur = head;
Node next = null;
//克隆每一个node并且将每一个node的下一个连接为自己克隆的node
while (cur != null) {
next = cur.next;
cur.next = new Node(cur.value);//克隆新节点
cur.next.next = next;
cur = next;
}
cur = head;
Node curCopy = null;
// 设置克隆节点的rand指针
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
curCopy.rand = cur.rand != null ? cur.rand.next : null;
cur = next;
}
Node res = head.next;
cur = head;
// 分离出来克隆节点
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
cur.next = next;
curCopy.next = next != null ? next.next : null;
cur = next;
}
return res;
}
题目六 两个单链表相交的一系列问题
给定两个可能有环也可能无环的单链表,头节点head1和head2。实现一个函数,如果两个链表相交,请返回相交的第一个节点。如果不相交,返回null。要求如果两个链表长度之和为N,时间复杂度达到,额外空间复杂度达到
。
(1) 首先补充一个判断一个单链表是否有环,没有直接返回false,有的话返回第一个入环节点的位置的方法。
1.先介绍需要使用额外空间的解决方法,从头开始遍历每一个节点,放入哈希表中,依次遍历,同时查询此时哈希表中是否含有此节点,如果没有,继续查询,直到为空证明无环;如果有,第一次重复的节点就是第一个入环节点。
2.下面介绍的这个方法是不需要额外空间的解决方法,设置快慢指针,都从头开始,快指针一次走两步,慢指针一次走一步,如果快指针走到空,那么证明单链表没有环;而如果两个指针相遇,证明有环,此时快指针回到第一个位置,慢指针原地不动,然后两个指针都一次只走一步,开始移动,两者将在第一个入环节点处相遇。
//找到链表第一个入环节点,如果无环,返回null
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;//如果head为空或者head下一个为空或者head下下一个节点为空,直接返回空
}
Node n1 = head.next; //慢指针
Node n2 = head.next.next; //快指针
while (n1 != n2) {
if (n2.next == null || n2.next.next == null) {//如果快指针下一个,下下一个不指向空
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
n2 = head; //快指针指向头部
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
(2)判断完两个单链表是否有环以后,可以分为以下两种情况(其他情况均不可能存在):
1.当两个单链表均没有环时,首先先判断两个单链表的尾节点地址是不是相同,如果两个单链表相交,那么尾节点的地址一定相同。如果不相同,则两者不相交,返回空。如果相同,寻找第一个相交节点,统计两条单链表的长度,然后开始扫描两个链表,让长链表先走差值步数,然后两个链表开始,依次扫描,直到两个指针所指的地址相同,则此时所指节点为第一个相交节点。
public static Node noLoop(Node head1, Node head2) {//两个单链表均无环
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1.next != null) {//统计第一个单链表的长度
n++;
cur1 = cur1.next;
}//cur1指向尾节点
while (cur2.next != null) {//计算第二个单链表的长度,得到的n是两者长度的差值
n--;
cur2 = cur2.next;
}//cur2指向尾节点
if (cur1 != cur2) {//如果两者尾节点地址不同,返回null
return null;
}
cur1 = n > 0 ? head1 : head2;//根据n的正负得出哪一个链表更长,cur1指向长链表
cur2 = cur1 == head1 ? head2 : head1;//cur2指向短链表
n = Math.abs(n);//对n取绝对值
while (n != 0) {
n--;
cur1 = cur1.next;
}//让长链表走差值步数
while (cur1 != cur2) {//对两个链表开始一一比对,相交时循环结束
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;//返回第一个相交节点
}
2.当两个链表均有环,具体实现代码如下:
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {//两个单链表均是有环节点,输入的分别是两个链表的头节点和入环节点
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {//当两个单链表的入环节点相同,和无环链表实现的方式相同
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
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 loop1;
}
cur1 = cur1.next;
}
return null;
}
}
对于整个问题的完整实现代码如下:每一部分的时间复杂度都是,空间复杂度也都是
。
public class Code FindFirstIntersectNode {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
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;
}
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node n1 = head.next; // n1 -> slow
Node n2 = head.next.next; // n2 -> fast
while (n1 != n2) {
if (n2.next == null || n2.next.next == null) {
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
n2 = head; // n2 -> walk again from head
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
}
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;
}
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
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 loop1;
}
cur1 = cur1.next;
}
return null;
}
}
public static void main(String[] args) {
// 1->2->3->4->5->6->7->null
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
// 0->9->8->6->7->null
Node head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
// 1->2->3->4->5->6->7->4...
head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
head1.next.next.next.next.next.next = head1.next.next.next; // 7->4
// 0->9->8->2...
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next; // 8->2
System.out.println(getIntersectNode(head1, head2).value);
// 0->9->8->6->4->5->6..
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
}
}