package com.interview.leetcode.list; import com.interview.leetcode.utils.ListNode; /** * Created_By: stefanie * Date: 14-11-15 * Time: 下午7:08 * * Given a singly linked list L: L0→L1→…→Ln-1→Ln, * * 1. reverse the linked list as Ln→Ln-1→...L1→L0 * reverse the whole list {@link Reverser} * reverse one part of the list, start at prev.next and end with tail {@link Reverser} * reverse one part of the list, from m ~ n {@link Reverser} * 2. interleaving two linked list {@link #interleaving} * first A0→A1→...An-1→An second B0→B1→...Bn-1→Bn * result A0→B0→A1→B1→...An-1→Bn-1→An→Bn * 3. if a linked list have cycle and the begin node of the cycle {@link #hasCycle} {@link #detectCycle} * 4. partition list by a given target, node smaller go before, and larger or equals go after. {@link #partition} * 5. sort list: better using merge sort, constant space and O(nlgn) move to {@link ListSort} * use length to partition list into two half, remember to set the tail to null when return list (length == 1) * 6. reverse nodes in k-group. * * Tricks: * 1. two pointer: fast and slow * 2. recursive: use return value or prev node in the parameter, the length of the list * 3. be careful when do pointer change, create temp node if needed. * */ public class ListOperation { public static ListNode getMiddle(ListNode node){ ListNode fast = node; ListNode slow = node; while(fast != null && fast.next != null){ fast = fast.next.next; slow = slow.next; } return slow; } public static ListNode getMiddlePre(ListNode node){ ListNode fast = node.next; ListNode slow = node; while(fast != null & fast.next != null){ fast = fast.next.next; slow = slow.next; } return slow; } /** * create temp node for both next */ public static void interleaving(ListNode first, ListNode second){ while(first != null && second != null){ ListNode firstNext = first.next; ListNode secondNext = second.next; first.next = second; if(firstNext == null) return; second.next = firstNext; first = firstNext; second = secondNext; } } public static ListNode interleavingMerge(ListNode l1, ListNode l2){ int index = 0; ListNode dummyHead = new ListNode(0); ListNode prev = dummyHead; while (l1 != null && l2 != null) { if ((index & 1) == 0) { prev.next = l1; l1 = l1.next; } else { prev.next = l2; l2 = l2.next; } prev = prev.next; index++; } if (l1 != null) prev.next = l1; else prev.next = l2; return dummyHead.next; } /** * detect if the given list have cycle */ public static boolean hasCycle(ListNode head) { if(head == null) return false; ListNode fast = head.next; ListNode slow = head; while(fast != null && fast.next != null &&fast != slow){ fast = fast.next.next; slow = slow.next; } return fast == slow; } /** * when init fast as head.next, when fast and slow meet, * slow should go one step ahead, in order to meet fast at the begin point */ public static ListNode detectCycle(ListNode head) { if(head == null) return null; ListNode fast = head.next; ListNode slow = head; while(fast != null && fast.next != null &&fast != slow){ fast = fast.next.next; slow = slow.next; } if(fast != slow) return null; slow = slow.next; //due to line 15, fast is one step ahead. fast = head; while(fast != slow){ fast = fast.next; slow = slow.next; } return fast; } /** * Given two list, detect if they have intersection, be ware of if the list have cycle */ public static boolean detectIntersection(ListNode l1, ListNode l2){ ListNode hasCycle1 = detectCycle(l1); ListNode hasCycle2 = detectCycle(l2); if(hasCycle1 == null && hasCycle2 == null){ while(l1.next != null) l1 = l1.next; while(l2.next != null) l2 = l2.next; return l1 == l2; } else if(hasCycle1 != null && hasCycle2 != null){ ListNode p1 = hasCycle1.next; while(p1 != hasCycle1 && p1 != hasCycle2) p1 = p1.next; return p1 == hasCycle2; } else return false; } /** * insert a number in a sorted cyclic list */ public static ListNode insert(ListNode head, int k){ ListNode pre = head; ListNode cur = head.next; while(cur.val >= k && cur != head){ cur = cur.next; pre = pre.next; } ListNode newNode = new ListNode(k); pre.next = newNode; newNode.next = cur; return k < head.val? newNode : head; } /** * create two dummy head small and large */ public static ListNode partition(ListNode head, int x) { if(head == null) return head; ListNode smallDummy = new ListNode(0); ListNode small = smallDummy; ListNode largeDummy = new ListNode(0); ListNode large = largeDummy; while(head != null){ if(head.val < x) { small.next = head; small = small.next; } else { large.next = head; large = large.next; } head = head.next; } large.next = null; small.next = largeDummy.next; return smallDummy.next; } public static int length(ListNode head){ int length = 0; while(head != null){ head = head.next; length++; } return length; } /** * 1. find the mid and tail using fast and slow pointer moving * 2. reverse the node from mid.next ~ tail * 3. do interleaving head and mid.next * remember to set mid.next = null to end the first list before run interleaving */ public static void reorderList(ListNode head) { if(head == null || head.next == null) return; ListNode slow = head; ListNode fast = head.next; while(fast != null && fast.next != null){ //1->2->3->4 slow is pre of mid fast = fast.next.next; slow = slow.next; } ListNode mid = ListReverser.reverse(slow.next); slow.next = null; interleaving(head, mid); } /** * Remove duplicated node */ public ListNode deleteDuplicatesOnce(ListNode head) { ListNode prev = head; while(prev != null && prev.next != null){ if(prev.next.val != prev.val){ prev = prev.next; } else { //1->1->2 prev.next = prev.next.next; //1->2 } } return head; } /** * Delete node appear more than once * @param head * @return */ public ListNode deleteDuplicates(ListNode head) { ListNode dummyHead = new ListNode(0); dummyHead.next = head; ListNode prev = dummyHead; ListNode front = head; while(front != null){ ListNode back = front.next; while(back != null && back.val == front.val) back = back.next; if(front.next == back){ //front is only appear once prev.next = front; prev = prev.next; } front = back; } prev.next = null; return dummyHead.next; } public static ListNode firstCommon(ListNode l1, ListNode l2){ int len1 = length(l1); int len2 = length(l2); if(len1 < len2){ ListNode tmp = l1; l1 = l2; l2 = tmp; } int longer = Math.max(len1, len2); int smaller = Math.min(len1, len2); while(longer > smaller && l1.val != l2.val){ l1 = l1.next; longer--; } while(l1 != null && l2 != null && l1.val != l2.val){ l1 = l1.next; l2 = l2.next; } return l1; } }