参考Leecode

环形链表

image.png
分析:
方式一:双指针法,我们可以用两个指针,一个快指针一次走两步,一个慢指针,一次走一步,若走到尾结点(next=null)那么表示无环,若快指针再次与慢指针相遇则存在环。
方式二:hash表,我们遍历所有结点并在map中存储每个结点的引用(或内存地址)。如果当前结点为空结点 nullptr(即已检测到链表尾部的下一个结点),那么我们已经遍历完整个链表,并且该链表不是环形链表。如果当前结点的引用已经存在于map中,那么返回 true(即该链表为环形链表)。

  1. public class 双指针 {
  2. public static void main(String[] args) {
  3. Node tail = new Node(1, null);
  4. Node n1 = new Node(2, tail);
  5. Node n2 = new Node(3, n1);
  6. Node n3 = new Node(4, n2);
  7. Node n4 = new Node(5, n3);
  8. Node n5 = new Node(6, n4);
  9. Node head = new Node(7, n5);
  10. tail.next = n4;
  11. System.out.println(hasCyc(head));
  12. }
  13. public static boolean hasCyc(Node head) {
  14. Node slowPtr = head;
  15. Node quickPtr = head;
  16. do {
  17. // 无环
  18. if (quickPtr == null || quickPtr.next == null) {
  19. return false;
  20. }
  21. // 移动指针
  22. slowPtr = slowPtr.next;
  23. quickPtr = quickPtr.next.next;
  24. } while (slowPtr != quickPtr);
  25. return true;
  26. }
  27. static class Node {
  28. int data;
  29. Node next;
  30. public Node(int data, Node next) {
  31. this.data = data;
  32. this.next = next;
  33. }
  34. }
  35. }
  1. public class HashDemo {
  2. public static void main(String[] args) {
  3. Node tail = new Node(1, null);
  4. Node n1 = new Node(2, tail);
  5. Node n2 = new Node(3, n1);
  6. Node n3 = new Node(4, n2);
  7. Node n4 = new Node(5, n3);
  8. Node n5 = new Node(6, n4);
  9. Node head = new Node(7, n5);
  10. tail.next = n4;
  11. System.out.println(hasCyc_hash(head));
  12. }
  13. public static boolean hasCyc_hash(Node head) {
  14. HashSet<Node> sets = new HashSet<>();
  15. Node ptr = head;
  16. // 遍历
  17. while (ptr != null) {
  18. // 已经存在表示有环
  19. if (sets.contains(ptr)) {
  20. return true;
  21. }
  22. // 不存在,添加到集合中
  23. sets.add(ptr);
  24. ptr = ptr.next;
  25. }
  26. return false;
  27. }
  28. static class Node {
  29. int data;
  30. Node next;
  31. public Node(int data, Node next) {
  32. this.data = data;
  33. this.next = next;
  34. }
  35. }
  36. }

环形链表二

image.png
分析:
image.png

  1. public class EntranceDemo {
  2. public static void main(String[] args) {
  3. Node tail = new Node(1, null);
  4. Node n2 = new Node(2, tail);
  5. Node n3 = new Node(3, n2);
  6. Node n4 = new Node(4, n3);
  7. Node n5 = new Node(5, n4);
  8. Node n6 = new Node(6, n5);
  9. Node head = new Node(7, n6);
  10. // 入口点测试
  11. tail.next = n5;
  12. System.out.println(cycEntrance(head));
  13. }
  14. public static int cycEntrance(Node head) {
  15. Node slowPtr = head;
  16. Node quickPtr = head;
  17. do {
  18. // 无环
  19. if (quickPtr == null || quickPtr.next == null) {
  20. return -1;
  21. }
  22. // 移动指针
  23. slowPtr = slowPtr.next;
  24. quickPtr = quickPtr.next.next;
  25. } while (slowPtr != quickPtr);
  26. // 有环,找入口点,将慢指针重新从head开始一次走一步,快指针从相遇的位置开始一次走一步,直到下次相遇
  27. slowPtr = head;
  28. while (slowPtr != quickPtr) {
  29. slowPtr = slowPtr.next;
  30. quickPtr = quickPtr.next;
  31. }
  32. return slowPtr.data;
  33. }
  34. static class Node {
  35. int data;
  36. Node next;
  37. public Node(int data, Node next) {
  38. this.data = data;
  39. this.next = next;
  40. }
  41. }
  42. }

输出:5

相交链表

image.png

image.png

删除链表的倒数第N个节点

image.png

反转链表

image.png