一、引言
链表是一种非线性数据结构,各种语言中给链表分配内存时不是一块整体的,可以充分利用碎片内存。相对线性的数据结构,链表对增加和删除节点比较高效,对读节点效率低一些。另外非线性结构需要保存下一个节点的指针,内存占用会大一些。
二、 高频面试题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public static ListNode reverse1(ListNode head, ListNode end) { if(head == end || head.getNext() == end) return head; ListNode pre = null; ListNode cur = head; while(cur != end) { ListNode next = cur.getNext(); cur.setNext(pre); pre = cur; cur = next; } return pre; }
public static ListNode reverse2(ListNode head) { if(head == null || head.getNext() == null) return head; ListNode next = head.getNext(); ListNode newHead = reverse2(next); next.setNext(head); head.setNext(null); return newHead; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public static ListNode reverseKGroup(ListNode head, int k) { ListNode dummy = new ListNode(-1); dummy.setNext(head); ListNode p = dummy; for(int i = 0; i < k; i++) { if(p == null || p.getNext() == null) return head; p = p.getNext(); } ListNode next = p.getNext(); ListNode g1Head = reverse1(head, next); ListNode g2Head = reverseKGroup(next, k); head.setNext(g2Head); return g1Head; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public static ListNode findTheMid(ListNode head) { if(head == null) return head; ListNode slow = head, fast = head; while(fast != null && fast.getNext() != null) { slow = slow.getNext(); fast = fast.getNext().getNext(); } return slow; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
private static boolean hasCycle(ListNode head) { if(head == null || head.getNext() == null) return false; ListNode slow = head, fast = head.getNext().getNext(); while(fast != null && fast.getNext() != null) { if(slow == fast) return true; slow = slow.getNext(); fast = fast.getNext().getNext(); } return false; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public static boolean isPalindrome(ListNode head) { ListNode mid = findTheMid(head); ListNode newHead = reverseToTheEnd(mid); while(head != null && newHead != null) { if(head.getVal() != newHead.getVal()) return false; head = head.getNext(); newHead = newHead.getNext(); } return true; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public static ListNode isIntersect(ListNode head1, ListNode head2) { ListNode p1 = head1; ListNode p2 = head2; while(p1 != null && p2 != null) { if(p1 == p2) return p1; p1 = p1.getNext(); if(p1 == null) p1 = head2; p2 = p2.getNext(); if(p2 == null) p2 = head1; } return null; }
|
三、总结
- 为了把对头节点和其他节点的处理统一,一般会加入dummy 节点。这样边界逻辑处理会少一些;
- 链表算法中关键点是前后节点指针的处理,需要避免构成循环;
- 多练、多推演。