🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 1 链表问题 > 面试时链表解题的方法论 > 对于笔试,不用太在乎空间复杂度,一切为了时间复杂度 > 对于面试,时间复杂度依然放在第一位,但是一定要找到空间最省的方法 ## 1.1 链表面试常用数据结构和技巧 1、 使用容器(哈希表,数组等) 2、 快慢指针 ### 1.1.1 快慢指针问题 1、 输入链表头结点,奇数长度返回中点,偶数长度返回上中点 > 1 3 5 2 7 返回 5;1 3 2 7 返回 3 2、 输入链表头结点,奇数长度返回中点,偶数长度返回中下点 > 1 3 5 2 7 返回 5;1 3 2 7 返回 2 3、 输入链表头结点,奇数长度返回中点前一个,偶数长度返回上中点前一个 > 1 3 5 2 7 返回 3;1 3 2 7 返回 1 4、 输入链表头结点,奇数长度返回中点前一个,偶数长度返回下中点前一个 > 1 3 5 2 7 返回 3;1 3 2 7 返回 3 ```Java package class06; import java.util.ArrayList; public class Code01_LinkedListMid { public static class Node { public int value; public Node next; public Node(int v) { value = v; } } // head 头 // 1、奇数长度返回中点,偶数长度返回上中点 public static Node midOrUpMidNode(Node head) { // 没有点,有一个点,有两个点的时候都是返回头结点 if (head == null || head.next == null || head.next.next == null) { return head; } // 链表有3个点或以上 // 快慢指针,快指针一次走两步,慢指针一次走一步 // 快指针走完,慢指针在中点位置 Node slow = head.next; Node fast = head.next.next; while (fast.next != null && fast.next.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } // 2、奇数长度返回中点,偶数长度返回中下点 public static Node midOrDownMidNode(Node head) { if (head == null || head.next == null) { return head; } Node slow = head.next; Node fast = head.next; while (fast.next != null && fast.next.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } // 3、奇数长度返回中点前一个,偶数长度返回上中点前一个 public static Node midOrUpMidPreNode(Node head) { if (head == null || head.next == null || head.next.next == null) { return null; } Node slow = head; Node fast = head.next.next; while (fast.next != null && fast.next.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } // 4、奇数长度返回中点前一个,偶数长度返回下中点前一个 public static Node midOrDownMidPreNode(Node head) { if (head == null || head.next == null) { return null; } if (head.next.next == null) { return head; } Node slow = head; Node fast = head.next; while (fast.next != null && fast.next.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } // 笔试可以用这种复杂点的方法,空间复杂度比上面快慢指针要高 public static Node right1(Node head) { if (head == null) { return null; } Node cur = head; ArrayList<Node> arr = new ArrayList<>(); while (cur != null) { arr.add(cur); cur = cur.next; } return arr.get((arr.size() - 1) / 2); } public static Node right2(Node head) { if (head == null) { return null; } Node cur = head; ArrayList<Node> arr = new ArrayList<>(); while (cur != null) { arr.add(cur); cur = cur.next; } return arr.get(arr.size() / 2); } public static Node right3(Node head) { if (head == null || head.next == null || head.next.next == null) { return null; } Node cur = head; ArrayList<Node> arr = new ArrayList<>(); while (cur != null) { arr.add(cur); cur = cur.next; } return arr.get((arr.size() - 3) / 2); } public static Node right4(Node head) { if (head == null || head.next == null) { return null; } Node cur = head; ArrayList<Node> arr = new ArrayList<>(); while (cur != null) { arr.add(cur); cur = cur.next; } return arr.get((arr.size() - 2) / 2); } public static void main(String[] args) { Node test = null; test = new Node(0); test.next = new Node(1); test.next.next = new Node(2); test.next.next.next = new Node(3); test.next.next.next.next = new Node(4); test.next.next.next.next.next = new Node(5); test.next.next.next.next.next.next = new Node(6); test.next.next.next.next.next.next.next = new Node(7); test.next.next.next.next.next.next.next.next = new Node(8); Node ans1 = null; Node ans2 = null; ans1 = midOrUpMidNode(test); ans2 = right1(test); System.out.println(ans1 != null ? ans1.value : "无"); System.out.println(ans2 != null ? ans2.value : "无"); ans1 = midOrDownMidNode(test); ans2 = right2(test); System.out.println(ans1 != null ? ans1.value : "无"); System.out.println(ans2 != null ? ans2.value : "无"); ans1 = midOrUpMidPreNode(test); ans2 = right3(test); System.out.println(ans1 != null ? ans1.value : "无"); System.out.println(ans2 != null ? ans2.value : "无"); ans1 = midOrDownMidPreNode(test); ans2 = right4(test); System.out.println(ans1 != null ? ans1.value : "无"); System.out.println(ans2 != null ? ans2.value : "无"); } } ``` ### 1.1.2 面试题一:判断回文结构 > 给定一个单链表的头结点head,请判断该链表是否为回文结构。回文就是正着输出和反着输出结果一样 1. 栈的方法特别简单(笔试用) > 笔试思路,以此把该链表放入栈中。再遍历该链表和栈中弹出的数比对,只要有不一样,就不是回文 2. 改原链表的方法需要注意边界问题(面试用) > 快慢指针解法:用快慢指针定位到中点的位置,奇数就是定位到唯一的中点,偶数定位到上中点。然后把中点右半部分加入栈中去,那么栈中存的是右半部分的逆序。接着从头遍历链表,栈中有多少个元素,我们就比较多少步,如果有对不上就不是回文 > 快慢指针最优解,不使用容器结构(stack),O(1):同样的找到中点位置,把右半部分指针回指到中点。接着指针1从L位置,指针2从R位置,往中间遍历。,每步比对,如果有不一样,则不是回文。返回答案之前,把中点右边的指针调整回来 ```Java package class06; import java.util.Stack; public class Code02_IsPalindromeList { public static class Node { public int value; public Node next; public Node(int data) { this.value = data; } } // need n extra space 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; } // need n/2 extra space // 中点右侧进栈 public static boolean isPalindrome2(Node head) { if (head == null || head.next == null) { return 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; } // need O(1) extra space // 不使用容器(stack)的方法 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) { // find mid node n1 = n1.next; // n1 -> mid n2 = n2.next.next; // n2 -> end } // n1 中点 n2 = n1.next; // n2 -> right part first node n1.next = null; // mid.next -> null Node n3 = null; // 右半部逆序指向中点 while (n2 != null) { // right part convert n3 = n2.next; // n3 -> save next node n2.next = n1; // next of right node convert n1 = n2; // n1 move n2 = n3; // n2 move } // 引入n3记录最后的位置,之后把右半部再逆序回原来的次序 n3 = n1; // n3 -> save last node n2 = head;// n2 -> left first node boolean res = true; while (n1 != null && n2 != null) { // check palindrome if (n1.value != n2.value) { res = false; break; } n1 = n1.next; // left to mid n2 = n2.next; // right to mid } n1 = n3.next; n3.next = null; // 把右半部分再逆序回来 while (n1 != null) { // recover list n2 = n1.next; n1.next = n3; n3 = n1; n1 = n2; } return res; } 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 head = null; printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(1); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); head.next.next = new Node(3); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); head.next.next = new Node(1); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); head.next.next = new Node(3); head.next.next.next = new Node(1); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); head.next.next = new Node(2); head.next.next.next = new Node(1); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); head.next.next = new Node(3); head.next.next.next = new Node(2); head.next.next.next.next = new Node(1); printLinkedList(head); System.out.print(isPalindrome1(head) + " | "); System.out.print(isPalindrome2(head) + " | "); System.out.println(isPalindrome3(head) + " | "); printLinkedList(head); System.out.println("========================="); } } ``` ### 1.1.3 面试题二:按值划分单链表 > 将单链表按某值划分成左边小,中间相等,右边大的形式 1. 把链表放入数组里,在数组上做partion(笔试用) > [3, 2, 4, 7, 0, 2, 1]选择2划分,基于2对数组作partion 2. 分成小、中、大三部分。再把各个部分之间串起来(面试用) > 借助6个引用变量,不需要容器O(N),且能保证稳定性。小于区域的头引用,小于区域的尾引用,等于区域的头引用,等于区域的尾引用,大于区域的头引用,大于区域的尾引用。依次对比给定的值加入到这三个区域,之后串联起来 ```Java package class06; public class Code03_SmallerEqualBigger { public static class Node { public int value; public Node next; public Node(int data) { this.value = data; } } // 方法1 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]; i = 0; cur = head; for (i = 0; i != nodeArr.length; i++) { nodeArr[i] = cur; cur = cur.next; } arrPartition(nodeArr, pivot); for (i = 1; i != nodeArr.length; i++) { nodeArr[i - 1].next = nodeArr[i]; } nodeArr[i - 1].next = null; // 返回头结点 return nodeArr[0]; } 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 mH = null; // big head Node mT = null; // big tail Node next = null; // save next node // 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 (mH == null) { mH = head; mT = head; } else { mT.next = head; mT = head; } } head = next; } // 小于区域的尾巴,连等于区域的头,等于区域的尾巴连大于区域的头 if (sT != null) { // 如果有小于区域 sT.next = eH; eT = eT == null ? sT : eT; // 下一步,谁去连大于区域的头,谁就变成eT } // 上面的if,不管跑了没有,et // all reconnect if (eT != null) { // 如果小于区域和等于区域,不是都没有 eT.next = mH; } return sH != null ? sH : (eH != null ? eH : mH); } 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 head1 = new Node(7); head1.next = new Node(9); head1.next.next = new Node(1); head1.next.next.next = new Node(8); head1.next.next.next.next = new Node(5); head1.next.next.next.next.next = new Node(2); head1.next.next.next.next.next.next = new Node(5); printLinkedList(head1); // head1 = listPartition1(head1, 4); head1 = listPartition2(head1, 5); printLinkedList(head1); } } ``` ### 1.1.4 面试题三 > 一种特殊的单链表结构如下: ```Java public static class Node { public int value; public Node next; public Node rand; public Node(int data) { this.value = data; } } ``` > rand指针式单链表节点结构中新增加的指针,rand可能指向链表中的任意一个节点,也可能为null。给定一个由Node节点类型组成的无环单链表节点head。请实现一个函数完成这个链表的复制,并返回复制的新链表的头结点。 > 要求时间复杂度为O(N),额外空间复杂度为O(1) 1. 哈希表方法(笔试推荐) > 第一步遍历,把所有节点加入到Map<Node, Node>表示老节点到克隆出来的节点映射 > 第二步遍历,查map找到克隆节点,最后返回头结点 2. 不用哈希表的方法,人为构造对应关系(面试推荐) > 第一步:每个节点遍历的时候克隆出来一个新的节点加入到当前节点和其next节点的中间 > 第二步:此时经过第一步所有节点和其克隆节点都是串在一起的,依次拿出当前节点和其克隆节点,当前节点的rand指针指向的节点的克隆节点给当前节点克隆的节点的rand节点指向的节点。 > 第三步:此时老节点的rand指针没变化,克隆节点的rand指针也都指向了对应的克隆节点。此时在大的链表上分离出来原链表和克隆链表 ```Java package class06; import java.util.HashMap; public class Code04_CopyListWithRandom { public static class Node { public int value; public Node next; public Node rand; public Node(int data) { this.value = data; } } // 方法1 public static Node copyListWithRand1(Node head) { HashMap<Node, Node> map = new HashMap<Node, Node>(); Node cur = head; while (cur != null) { // 当前节点,克隆出来一个相同值的新节点加入字典 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); cur = cur.next; } // 返回head对应的克隆节点 return map.get(head); } // 方法二 public static Node copyListWithRand2(Node head) { if (head == null) { return null; } Node cur = head; Node next = null; // 克隆出来的node放在原本node和next指向的node中间 // 1 -> 2 // 1 -> 1' -> 2 while (cur != null) { // cur 老 next 老的下一个 next = cur.next; cur.next = new Node(cur.value); cur.next.next = next; cur = next; } cur = head; Node curCopy = null; // set copy node rand // 1 -> 1' -> 2 -> 2' // 设置新的克隆节点间的rand节点 while (cur != null) { // cur 老 // cur.next => 新的 copy出来的节点 next = cur.next.next; curCopy = cur.next; curCopy.rand = cur.rand != null ? cur.rand.next : null; cur = next; } // 老的头结点:head 新克隆出来的头结点: head.next Node res = head.next; cur = head; // split,分离原本节点组成的链表和克隆节点组成的链表 while (cur != null) { next = cur.next.next; curCopy = cur.next; cur.next = next; curCopy.next = next != null ? next.next : null; cur = next; } return res; } public static void printRandLinkedList(Node head) { Node cur = head; System.out.print("order: "); while (cur != null) { System.out.print(cur.value + " "); cur = cur.next; } System.out.println(); cur = head; System.out.print("rand: "); while (cur != null) { System.out.print(cur.rand == null ? "- " : cur.rand.value + " "); cur = cur.next; } System.out.println(); } public static void main(String[] args) { Node head = null; Node res1 = null; Node res2 = null; printRandLinkedList(head); res1 = copyListWithRand1(head); printRandLinkedList(res1); res2 = copyListWithRand2(head); printRandLinkedList(res2); printRandLinkedList(head); System.out.println("========================="); head = new Node(1); head.next = new Node(2); head.next.next = new Node(3); head.next.next.next = new Node(4); head.next.next.next.next = new Node(5); head.next.next.next.next.next = new Node(6); head.rand = head.next.next.next.next.next; // 1 -> 6 head.next.rand = head.next.next.next.next.next; // 2 -> 6 head.next.next.rand = head.next.next.next.next; // 3 -> 5 head.next.next.next.rand = head.next.next; // 4 -> 3 head.next.next.next.next.rand = null; // 5 -> null head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4 printRandLinkedList(head); res1 = copyListWithRand1(head); printRandLinkedList(res1); res2 = copyListWithRand2(head); printRandLinkedList(res2); printRandLinkedList(head); System.out.println("========================="); } } ``` ### 1.1.5 面试题四 > 该问题和约舍夫环问题是链表问题的比较难的问题 > 题目描述:给定两个可能有环也可能无环的单链表,头结点head1和head2。请实现一个函数,如果两个链表相交,请返回相交的第一个节点。如果不相交,返回null > 要求:如果两个链表长度之和为N,时间复杂度请达到O(N),额为空间复杂度请达到O(1) > 思路:由于是单链表,则一旦成环就结束,出不来,因为每个节点只有一个Next指针 1. 方法一:用set把每个节点的内存地址放到set里面,如果存在相同的内存在set中存在,则就是第一个成环的节点 2. 用快慢指针对链表遍历,那么快慢指针一定会相遇,能相遇就说明存在环。然后让慢指针停在相遇的位置,快指针回到头结点。快指针和慢指针再出发且快指针也变成一次走一步和满指针相同,再次相遇的节点就是成环节点 ```Java package class06; public class Code05_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; } // head1的第一个入环节点 Node loop1 = getLoopNode(head1); // head2的第一个入环节点 Node loop2 = getLoopNode(head2); // 两个无环链表是否相交的情况 // 由于每个节点只有一个next指针,则如果两个无环相交则相交之后就只剩下公共部分 // 方法1把第一条链表放到set中,第二个链表依次查在不在该set中,第一个找到的就是 // 方法2 // 把链表1走到尾结点end1,记录长度l1 // 把链表1走到尾结点end2,记录长度l2 // 如果end1和end2的内存地址不同一定不相交 // 如果end1==end2,则(1)长的链表从头结点先走保证和短链表相同长度的位置,再以此往下走,第一次相同节点 // (2)则依次从尾结点出发,找第一次出现内存地址不相同的那个节点,该节点的next节点就是第一次相交的节点 if (loop1 == null && loop2 == null) { return noLoop(head1, head2); } // 一个为空,另外一个不为空不可能相交。两个都不为空的情况下共用一个环 if (loop1 != null && loop2 != null) { return bothLoop(head1, loop1, head2, loop2); } return null; } // 找到链表第一个入环节点,如果无环,返回null public static Node getLoopNode(Node head) { if (head == null || head.next == null || head.next.next == null) { return null; } // n1 慢 n2 快 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; } // 能相遇则跳出while,快指针回到开头,满指针停在原地 n2 = head; // n2 -> walk again from head while (n1 != n2) { // 此时快慢指针每次移动相同步数 n1 = n1.next; n2 = n2.next; } return n1; } // 如果两个链表都无环,返回第一个相交节点,如果不想交,返回null 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; } // n : 链表1长度减去链表2长度的值 // 谁长,谁的头变成cur1 cur1 = n > 0 ? head1 : head2; // 谁短,谁的头变成cur2 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; } // 两个有环链表,返回第一个相交节点,如果不想交返回null // head1的入环节点是loop1,head2的入环节点是loop2 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 { //否则,找第一个成环节点转回自身的过程中遇到loop2,则相交,否则不相交 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); } } ``` ### 1.1.6 面试题五 > 题目描述:能不能不给单链表的头结点,只给想要删除的节点,就能做到在链表上把这个点删掉? 1. 抖机灵的做法,1->2->3->4->5->null,给定3。那么根据内存地址找到3这个节点,把3下个节点赋值给自身变成4,再把自身的下一个指针指向下下个值5即可。1->2->4->5->null。缺点没把原始节点删除,只是改变了值,内存地址没被删掉而是删掉了需要删除节点的下一个内存地址。该方法无法删除链表的最后一个节点 > 实质上不给头结点,无法删除给定的节点。没有头结点,没法准确的连指针 ```Java package class06; public class Test { public static class Node{ public int value; public Node next; public Node(int v) { value = v; } } public static void main(String[] args) { Node a = new Node(1); Node b = new Node(2); Node c = new Node(3); a.next = b; b.next = c; // 实质上这里置为空没用,只是把Java栈中的变量不指向堆中的3节点 //堆中的结构没改变,3节点并没有被删除 c = null; } } ```