Showing posts with label linked list. Show all posts
Showing posts with label linked list. Show all posts

Monday, January 16, 2017

Reverse Second Half Linked List

Given a linked list, reverse the second half linked list. If the list length is odd, then the middle list node also should be reversed.

For example:
Given:  1 -> 2 -> 3 -> null;
Return: 1 -> 3 -> 2 -> null;

Given:  1 -> 2 -> 3 -> 4 -> null;
Return: 1 -> 2 -> 4 -> 3 -> null;

/*
First compute the size of list to determine the middle list node.

time:O(n), space:O(1)
*/

import java.util.*;

class ListNode {
    int val;
    ListNode next;
    public ListNode(int val) {
        this.val = val;
        next = null;
    }
}

public class Solution {
    public static ListNode reverseHalfList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        int size = calSize(head);
        ListNode middle = getMidNode(head, size);
        middle.next = reverse(middle.next);
        return head;
    }
    public static int calSize(ListNode head) {
        int size = 0;
        while (head != null) {
            head = head.next;
            size++;
        }
        return size;
    }
    public static ListNode getMidNode(ListNode head, int size) {
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode slow = (size & 1) == 0 ? head : dummy;
        ListNode fast = head.next;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
    public static ListNode reverse(ListNode head) {
        ListNode newHead = null;
        while (head != null) {
            ListNode temp = head.next;
            head.next = newHead;
            newHead = head;
            head = temp;
        }
        return newHead;
    }

    public static void main(String[] args) {
        ListNode n1 = new ListNode (1);
        ListNode n2 = new ListNode (2);
        ListNode n3 = new ListNode (3);
        ListNode n4 = new ListNode (4);
        ListNode n5 = new ListNode (5);
        ListNode n6 = new ListNode (6);
        ListNode n7 = new ListNode (7);
        n1.next = n2;
        n2.next = n3;
        n3.next = n4;
        
        n5.next = n6;
        n6.next = n7;
        ListNode ans1 = reverseHalfList(n1);
        ListNode ans2 = reverseHalfList(n5);
        while (ans1 != null) {
            System.out.print(ans1.val + " ");
            ans1 = ans1.next;
        }
        System.out.println(" ");
        while (ans2 != null) {
            System.out.print(ans2.val + " ");
            ans2 = ans2.next;
        }
    }
}

Sunday, January 15, 2017

LRU Cache Miss

Implement LRU cache, and count the miss number which is not in the cache before added to the cache. 

import java.util.*;

class ListNode {
    int key;
    ListNode prev, next;
    public ListNode(int key) {
        this.key = key;
        prev = next = null;
    }
}
public class Solution {
    public static int cacheMiss(int[] array, int size) {
        if (array == null || array.length == 0 || size <= 0) {
            return 0;
        }
        Map<Integer, ListNode> cache = new HashMap<>();
        ListNode head = new ListNode(-1);
        ListNode tail = new ListNode(-1);
        head.next = tail;
        tail.prev = head;
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            ListNode newNode = new ListNode(array[i]);
            if (!cache.containsKey(array[i])) {
                if (cache.size() == size) {
                    cache.remove(head.next.key);
                    head.next = head.next.next;
                    head.next.prev = head;
                }
                count++;
            } else {
                ListNode node = cache.get(array[i]);
                node.prev.next = node.next;
                node.next.prev = node.prev;
            }
            newNode.prev = tail.prev;
            newNode.next = tail;
            tail.prev = newNode;
            newNode.prev.next = newNode;
            cache.put(array[i], newNode);
        }
        return count;
    }

    public static void main(String[] args) {
        int[] A = {1,2,3,1,4,3};
        int res = cacheMiss(A, 3);
        System.out.println(res);
    }
}

LRU Cache

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

/*
LinkedHashMap = DoublyLinkedList + HashMap.
Newest node append to tail and eldest node remove from head.
Notice: 
1. When use DoublyLinkedList, ListNode head and tail should be initialized at first.
2. In the ListNode, key should be added. 
*/

public class Solution {
    private class ListNode {
        ListNode prev;
        ListNode next;
        int key;
        int value;
        public ListNode(int key, int value) {
            this.key = key;
            this.value = value;
            prev = null;
            next = null;
        }
    }
    
    private int capacity;
    private Map<Integer, ListNode> map = new HashMap<>();
    private ListNode head = new ListNode(-1, -1);
    private ListNode tail = new ListNode(-1, -1);
    
    public Solution(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        ListNode temp = map.get(key);
        temp.prev.next = temp.next;
        temp.next.prev = temp.prev;
        moveToTail(temp);
        
        return map.get(key).value;
    }

    public void set(int key, int value) {
        if (get(key) != -1) {
            map.get(key).value = value;
            return;
        }
        if (map.size() == capacity) {
            //This is why key should be added to the ListNode.
            map.remove(head.next.key);  
            head.next = head.next.next;
            head.next.prev = head;
        }
        
        ListNode node = new ListNode(key, value);
        map.put(key, node);
        moveToTail(node);
    }
    
    private void moveToTail(ListNode node) {
        node.prev = tail.prev;
        node.next = tail;
        tail.prev = node;
        node.prev.next = node;
    }

Linked List Cycle II

Given a linked list, return the node where the cycle begins.
If there is no cycle, return null.
For example:
Given -21->10->4->5, tail connects to node index 1,return 10

/**
 * Definition for ListNode.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int val) {
 *         this.val = val;
 *         this.next = null;
 *     }
 * }
 */ 

/*
time:O(n), space:O(1)
*/

public class Solution {
    public ListNode detectCycle(ListNode head) { 
        if (head == null) {
            return head;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return null;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        while (head != slow.next) {
            head = head.next;
            slow = slow.next;
        }
        return head;
    }
}

Insert into Cycle Linked List

Insert a new list node into a sorted cycle linked list.

/*
time:O(n), space:O(1)
*/

import java.util.*;

class ListNode {
    int val;
    ListNode next;
    public ListNode(int val) {
        this.val = val;
        next = null;
    }
}
public class Solution {
    public static ListNode insertCycleLinkedList(ListNode head, 
                                                 int val) {
        ListNode curr = new ListNode(val);
        if (head == null) {
            curr.next = curr;
            return curr;
        }
        ListNode node = head;
        do {
            if (val >= node.val && val <= node.next.val) {
                break;
            } 
            if (node.val >= node.next.val && 
                (val >= node.val || val <= node.next.val)) {
                break;
            }
            node = node.next;
        } while (node != head);
        
        curr.next = node.next;
        node.next = curr;
        return curr;
    }

    public static void main(String[] args) {
        ListNode n1 = new ListNode (1);
        ListNode n2 = new ListNode (1);
        ListNode n3 = new ListNode (1);
        n1.next = n2;
        n2.next = n3;
        n3.next = n1;
        ListNode ans = insertCycleLinkedList(n1, 2);
        ListNode tmp = ans;
        do {
            System.out.print(tmp.val + " ");
            tmp = tmp.next;
        } while (tmp != ans);
    }
}

Saturday, January 14, 2017

Merge Two Sorted Lists



Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */

/*
time:O(n), space:O(1)
*/
public class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                curr.next = l1;
                l1 = l1.next;
            } else {
                curr.next = l2;
                l2 = l2.next;
            }
            curr = curr.next;
        }
        if (l1 != null) {
            curr.next = l1;
        }
        if (l2 != null) {
            curr.next = l2;
        }
        return dummy.next;
    }
}

Sunday, January 8, 2017

Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example
Given lists:
[
  2->4->null,
  null,
  -1->null
],
return -1->2->4->null.


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */

/*
First put all the ListNode in the input array into the min-heap. Every time,  pop out the ListNode with the smallest value. If this ListNode's next node is not null, then push the next ListNode into the min-heap. 

PriorityQueue. time: O(NlogK), space: O(K), N: the number of all the ListNode,K: the length of the input lists array.
*/

public class Solution {
    private Comparator<ListNode> ListNodeComparator = new                                                Comparator<ListNode>() {
        public int compare(ListNode a, ListNode b) {
            return a.val - b.val;    //b.val-a.val, descending sort.
        }
    };
    public ListNode mergeKLists(ListNode[] lists) {  
        if (lists == null || lists.length == 0) {
            return null;
        }
        Queue<ListNode> heap = new PriorityQueue<>(lists.length,                                                   ListNodeComparator); 
        for (ListNode node : lists) {
            if (node != null) {
                heap.offer(node); 
            }
        }
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (!heap.isEmpty()) {
            ListNode head = heap.poll();
            tail.next = head;
            tail = head;
            if (head.next != null) {
                heap.offer(head.next);
            }
        }
        return dummy.next;
    }
}


//divide & conquer, recursion, time: O(NlogK), space: O(1)
public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        return mergeHelper(lists, 0, lists.length - 1);
    }
    public ListNode mergeHelper(ListNode[] lists, int start, int end) {
        if (start == end) {
            return lists[start];
        }
        int mid = start + (end - start) / 2;
        ListNode left = mergeHelper(lists, start, mid);
        ListNode right = mergeHelper(lists, mid + 1, end);
        
        return mergeTwoLists(left, right);
    }
    private ListNode mergeTwoLists(ListNode head1, ListNode head2) {
        ListNode dummy = new ListNode(0);
        ListNode temp = dummy;
        while (head1 != null && head2 != null) {
            if (head1.val < head2.val) {
                temp.next = head1;
                head1 = head1.next;
            } else {
                temp.next = head2;
                head2 = head2.next;
            }
            temp = temp.next;
        }
        if (head1 != null) {
            temp.next = head1;
        } else {
            temp.next = head2;
        }
        return dummy.next;
    }
}


//merge two by two, iteration, time: O(NlogK), space: O(K)
public class Solution {
    private ListNode mergeTwoLists(ListNode head1, ListNode head2) {
        ListNode dummy = new ListNode(0);
        ListNode temp = dummy;
        while (head1 != null && head2 != null) {
            if (head1.val < head2.val) {
                temp.next = head1;
                head1 = head1.next;
            } else {
                temp.next = head2;
                head2 = head2.next;
            }
            temp = temp.next;
        }
        if (head1 != null) {
            temp.next = head1;
        } else {
            temp.next = head2;
        }
        return dummy.next;
    }
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        int index = 0;
        while (lists.length > 1) {
            int l = lists.length;
            ListNode[] newList = new ListNode[(l + 1) / 2];
            for (int i = 0; i + 1 < l; i += 2) {
                ListNode temp = mergeTwoLists(lists[i], 
                                              lists[i + 1]);
                newList[index++] = temp;
            }
            if (l % 2 == 1) {
                newList[index] = lists[l - 1];
            }
            lists = newList;
            index = 0;
        }
        return lists[0];
    }
}


//merge two by two, iteration, time: O(NlogK), space: O(1)
public class Solution {
    private ListNode mergeTwoLists(ListNode head1, ListNode head2) {
        ListNode dummy = new ListNode(0);
        ListNode temp = dummy;
        while (head1 != null && head2 != null) {
            if (head1.val < head2.val) {
                temp.next = head1;
                head1 = head1.next;
            } else {
                temp.next = head2;
                head2 = head2.next;
            }
            temp = temp.next;
        }
        if (head1 != null) {
            temp.next = head1;
        } else {
            temp.next = head2;
        }
        return dummy.next;
    }
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        int size = lists.length;
        while (size > 1) {
            for (int i = 0, j = size - 1; i < j; i++, j--) {
                lists[i] = mergeTwoLists(lists[i], lists[j]);
            }
            size = (size + 1) / 2;
        }
        return lists[0];
    }
}

Saturday, January 7, 2017

Reverse Linked List

Reverse a singly linked list.


/**

 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
/*First initialize a pointer 'newHead' pointing to null. In each iteration, we do four steps.
1. New a 'tmp' pointer pointing to 'head.next';
2. Let 'head.next' connect to 'newHead';
3. Let 'newHead' point to 'head';
4. Let 'head' point to 'tmp'.

time: O(n), space:O(1)
*/

public class Solution {

    public ListNode reverseList(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode newHead = null;
        while (head != null) {
            ListNode tmp = head.next;
            head.next = newHead;
            newHead = head;
            head = tmp;
        }
        return newHead;
    }
}