第二阶段-day03_Linked
今天我们主要讲了一些链表的练习题,希望大家可以从中体会链表的使用方式,加深对链表的理解。
回顾昨天内容:
总结: List List subList(int fromIndex, int toIndex) 视图技术 ListIterator listIterator() ListIterator listIterator(int index) ListIterator 概述:列表特有的迭代器 API: boolean hasNext() boolean hasPrevious() E next() E previous() int previousIndex() int nextIndex() void add(E e) void remove() void set(E e) 数组 Q1 Q2 Q3 数组的基本操作 总结:增删慢,查找快 链表 概述: 分类: 单链表 双向链表 循环链表 双向循环链表 单链表的操作 双向链表的操作 例子: a. LRU算法 b. 求单表的中间元素 c. 判断单链表是否有环
3个练习:
1 package com.cskaoyan.exercise; 2 3 public class Node { 4 int value; 5 Node next; 6 7 public Node(int value) { 8 this.value = value; 9 } 10 11 public Node(int value, Node next) { 12 this.value = value; 13 this.next = next; 14 } 15 16 @Override 17 public String toString() { 18 return "Node{" + 19 "value=" + value + 20 '}'; 21 } 22 }
Ex2:
方法1. 给一个阈值(10ms),如果在遍历链表的过程中10ms还没有结束,就认为有环。
2. 迷雾森林
1 package com.cskaoyan.exercise; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.HashSet; 6 7 /* 8 判断链表中是否有环 9 1. 给一个阈值(10ms),如果在遍历链表的过程中10ms还没有结束,就认为有环。 10 2. 迷雾森林 11 Collection visited = new ArrayList(); 12 a.遍历链表,获取每一个结点。 13 判断结点是否在visited集合中存在。 14 存在:返回true 15 不存在:将该结点添加到visited中,然后遍历下一个结点 16 b.遍历结束后,返回false 17 3. 跑道(快慢指针) 18 a.创建了快指针和慢指针,快指针每次走两步,慢指针每次走一步 19 b.遍历链表 20 如果快指针到到终点:返回false 21 如果快指针和慢指针相遇:返回true 22 快指针移动两步 23 慢指针移动一步 24 */ 25 public class Ex1 { 26 /* 27 时间复杂度:O(n^2) --> O(n) 28 空间复杂度:O(n) 29 */ 30 /*public static boolean hasCircle(Node head) { 31 // Collection visited = new ArrayList(); 32 Collection visited = new HashSet(); 33 Node x = head; 34 while (x != null) { 35 if (visited.contains(x)) return true; 36 visited.add(x); 37 x = x.next; 38 } 39 // 遍历结束 40 return false; 41 }*/ 42 43 /* 44 时间复杂度: 45 最好情况:O(a) 46 最坏情况:O(a+r) 47 平均情况:O(a+r/2) 48 空间复杂度:O(1) 49 */ 50 public static boolean hasCircle(Node head) { 51 // 创建快慢指针 52 Node fast = head; 53 Node slow = head; 54 // 遍历链表 55 do { 56 // 快指针是否到达终点 57 if (fast == null || fast.next == null) return false; 58 fast = fast.next.next; 59 slow = slow.next; 60 } while (fast != slow); 61 // fast == slow 62 return true; 63 } 64 65 public static void main(String[] args) { 66 // 1 --> 2 --> 3 --> 4 67 /*Node head = new Node(4); 68 head = new Node(3, head); 69 head = new Node(2, head); 70 head = new Node(1, head); 71 System.out.println(hasCircle(head));*/ 72 73 // 1 --> 2 --> 3 --> 4 --> 2 --> ... 74 /*Node node = new Node(4); 75 Node head = new Node(3, node); 76 head = new Node(2, head); 77 node.next = head; 78 head = new Node(1, head); 79 System.out.println(hasCircle(head));*/ 80 81 // 1 --> 2 --> 3 --> 4 --> 4 --> ... 82 Node node = new Node(4); 83 node.next = node; 84 Node head = new Node(3, node); 85 head = new Node(2, head); 86 head = new Node(1, head); 87 System.out.println(hasCircle(head)); 88 } 89 }
方法2. 跑道(快慢指针)
判断链表是否有环--快慢指针
1 package com.cskaoyan.exercise; 2 3 import java.util.Collection; 4 import java.util.HashSet; 5 6 /* 7 如果有环:返回入环的第一个结点 8 如果无环:返回null 9 1. 迷雾森林 10 Collection visited = new ArrayList(); 11 a.遍历链表,获取每一个结点。 12 判断结点是否在visited集合中存在。 13 存在:返回该节点 14 不存在:将该结点添加到visited中,然后遍历下一个结点 15 b.遍历结束后,返回null 16 2. 跑道(快慢指针) 17 */ 18 public class Ex2 { 19 /* 20 时间复杂度:O(n) 21 空间复杂度:O(n) 22 */ 23 /*public static Node hasCircle(Node head) { 24 Collection visited = new HashSet(); 25 Node x = head; 26 while (x != null) { 27 if (visited.contains(x)) return x; 28 visited.add(x); 29 x = x.next; 30 } 31 return null; 32 }*/ 33 34 /* 35 时间复杂度: 36 最好情况:O(2a) 37 最坏情况:O(2a+r) 38 平均情况:O(2a+r/2) 39 空间复杂度:O(1) 40 */ 41 public static Node hasCircle(Node head) { 42 Node fast = head; 43 Node slow = head; 44 do { 45 if (fast == null || fast.next == null) return null; 46 fast = fast.next.next; 47 slow = slow.next; 48 } while (fast != slow); 49 // fast == slow 50 // 将fast移动到开头 51 fast = head; 52 while (fast != slow) { 53 fast = fast.next; 54 slow = slow.next; 55 } 56 // fast == slow 再一次相遇 57 return fast; 58 } 59 60 public static void main(String[] args) { 61 // 1 --> 2 --> 3 --> 4 62 Node head = new Node(4); 63 head = new Node(3, head); 64 head = new Node(2, head); 65 head = new Node(1, head); 66 System.out.println(hasCircle(head)); 67 68 // 1 --> 2 --> 3 --> 4 --> 2 --> ... 69 /*Node node = new Node(4); 70 Node head = new Node(3, node); 71 head = new Node(2, head); 72 node.next = head; 73 head = new Node(1, head); 74 System.out.println(hasCircle(head));*/ 75 76 // 1 --> 2 --> 3 --> 4 --> 4 --> ... 77 /*Node node = new Node(4); 78 node.next = node; 79 Node head = new Node(3, node); 80 head = new Node(2, head); 81 head = new Node(1, head); 82 System.out.println(hasCircle(head));*/ 83 } 84 }
Ex3:反转单链表
方法1:头插法
1 package com.cskaoyan.exercise; 2 3 /* 4 反转单链表 5 举例: 6 输入:1 --> 2 --> 3 --> null 7 输出:3 --> 2 --> 1 --> null 8 1.头插法 9 2.递归 10 */ 11 public class Ex3 { 12 public static Node reverse(Node head) { 13 Node prev = null; 14 Node curr = head; 15 while (curr != null) { 16 // 保留下一个结点 17 Node next = curr.next; 18 // 头插法 19 curr.next = prev; 20 prev = curr; 21 // curr移动到下一个结点 22 curr = next; 23 } 24 return prev; 25 } 26 27 public static void print(Node head) { 28 Node x = head; 29 while (x != null) { 30 System.out.print(x.value); 31 if (x.next != null) System.out.print(" --> "); 32 x = x.next; 33 } 34 System.out.println(); 35 } 36 37 public static void main(String[] args) { 38 Node head = new Node(3); 39 head = new Node(2, head); 40 head = new Node(1, head); 41 print(head); 42 head = reverse(head); 43 print(head); 44 } 45 }
方法二:递归