AdSense

Showing posts with label Linked List. Show all posts
Showing posts with label Linked List. Show all posts

Friday, August 19, 2016

Linked List Random Node

Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen.
Follow up:
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?
Example:


// Init a singly linked list [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);

// getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.
solution.getRandom();


A probability problem. The easiest solution is to traverse the whole list, find the count (number of nodes in the list) and randomly pick one node with 1 / count probability. As the question mentioned, if the list is too long, it will be too hard to get the length. One approach is to keep counting and choose the position at 1 / count. Traverse through the whole list and return the last number. The intuition is, for any number x, the probability is : 1 / x * (x / (x + 1))... (n - 1)/n = 1 / n.


public class Solution {
    
    ListNode head;
    Random random;

    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
    public Solution(ListNode head) {
        this.head = head;
        random = new Random();
    }
    
    /** Returns a random node's value. */
    public int getRandom() {
        ListNode curr = head;
        int toReturn = 0;
        for (int cnt = 1; curr != null; cnt++, curr = curr.next) {
            if (random.nextInt(cnt) == 0) {
                toReturn = curr.val;
            }
        }
        return toReturn;
    }
}


Friday, May 22, 2015

Singly linked list using Python, iterator in a Python object

The singly linked list is nothing fancy, basically it is a list of nodes appended one after another. Each node has a pointer points to its successor.

class _ListNode:

    def __init__(self, data):
        self.data = data
        self.next = None


Since any node can only be accessed by its predecessor, traversing the list to search for a node takes O(n) time. If we keep tracking the current tail of the node, adding a new node only requires us to append the new node to the tail of the list, thus takes O(1) time. Deleting a node, on the other hand, requires traversing the list to find the node to delete, thus takes O(n) time.

Here is the source code.

class _ListNode:

    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedList:
    def __init__(self):
        self._head = _ListNode(-1) #sentinel node
        self._curr = self._head
        self._size = 0

    def __len__(self):
        return self._size

    def __add__(self, data):
        """
        append a new node
        """
        self._curr.next = _ListNode(data)
        self._curr = self._curr.next
        self._size += 1

    def __contains__(self, item):
        """
        check if a given item is in the list
        :param item:
        :return:
        """
        curNode = self._head.next
        while curNode is not None and curNode.data != item:
            curNode = curNode.next
        return curNode is not None

    def __delattr__(self, item):
        """
        delete a node if exists in the list
        :param item:
        :return:
        """
        curNode = self._head.next
        while curNode is not None \
                and curNode.next is not None \
                and curNode.next.data != item:
            curNode = curNode.next
        if curNode.next is None:
            print('No such item in the linked list!')
            return False
        else:
            curNode.next = curNode.next.next
            self._size -= 1
            return True

    def __iter__(self):
        curNode = self._head.next
        assert curNode is not None, 'Empty list!'
        while curNode is not None:
            data = curNode.data
            #print(curNode.data)
            curNode = curNode.next
            yield data

One more thing I learned today about Python is the iterator of an object. When we write a data structure using Python, we sometimes write __iter__() function. This function will return an iterator of the object. So next time when you write:

for item in object:

The compiler will call __iter__() and return the items in the object based on your __iter__() function.
Another useful places for this function is that you can initialize a list. For example, if I want to create a list based on the items in the above linked list, I can simply do:

tolist = list(linkedlist)


Wednesday, January 28, 2015

Linked List

There is an interview question asked about what data structure can be used to perform insertion and removal in FIFO. The answer is Singly - linked list with head and tail pointers. This motivated me to summarize the linked list structure.


Singly-Linked List with head and tail pointers

This is the answer for the above question. The singly linked list is a sequence of dynamically allocated storage elements, each containing a pointer to its successor. Keeping a second pointer, tail, which points to the last element of the list, allows the retrieve and remove elements in O(1) time.

How?

Adding at tail and remove at the head.
public class SinglyLinkedList {
 protected ListNode head;
 protected ListNode tail;
 protected long size;
 
 public SinglyLinkedList() {
  head = null;
  tail = null;
  size = 0;
 }
 /**
  * add to the head
  */
 public void add(T value) {
  ListNode node = new ListNode (value);
  //if no node is in the list, 
  //set the tail to the first node added to the list
  if (tail == null)
   tail = node;
  node.setNext(head);
  head = node;
  size++;
 }
 /**
  * insert a node at desired position
  * @param curr
  * @param toInsert
  * O(n)
  */
 public void insert(int index, T value) {
  if (index < 0 || index > size - 1)
   throw new IllegalArgumentException("index must be greater than 0 and less than number of elements in the list!");
  
  if (index == 0) {
   add(value);
   return;
  }
  if (index == size - 1) {
   addLast(value);
   return;
  }
  ListNode toInsert = new ListNode (value);
  ListNode prev = getNode(index - 1);
  ListNode next = prev.getNext();
  prev.setNext(toInsert);
  toInsert.setNext(next);
 }
 
 
 /**
  * add the node at tail
  * O(1)
  */
 public void addLast(T value) {
  ListNode node = new ListNode (value);
  if (head == null) {
   head = node;
  }
  else {
   tail.setNext(node);
  }
  node.setNext(null);
  tail = node;
  size++;
 }
 /**
  * remove the first element in the list
  * O(n)
  * @return
  */
 public ListNode removeFirst() {
  if (head == null)
   throw new NullPointerException("Empty list!");
  ListNode tmp = head;
  head = head.getNext();
  tmp.setNext(null);
  size--;
  return tmp;
 }
 /**
  * need to traverse the list
  * @return
  */
 public ListNode removeLast() {
  if (size == 0)
   throw new NullPointerException("Empty list!");
  ListNode node = head;
  ListNode toRemove = tail;
  while (!node.getNext().equals(tail))
   node = node.getNext();
  node.setNext(null);
  tail = node;
  size--;
  return toRemove; 
 }
 /**
  * remove a node
  * @param node
  * O(n)
  */
 public void remove(ListNode toRemove) {
  if (size == 0)
   throw new NullPointerException("Empty list!");
  if (toRemove.equals(head))
   removeFirst();
  if (toRemove.equals(tail))
   removeLast();
  ListNode node = head;
  while (node != null && !node.getNext().equals(toRemove)) {
   node = node.getNext();
  }
  if (node == null)
   throw new IllegalArgumentException("No such element in the list!");
  node.setNext(node.getNext().getNext());
 }
 public ListNode getFirst() {
  return head;
 }
 public ListNode getLast() {
  return tail;
 }
 public long getSize() {
  return size;
 }
 public void clear() {
  for (ListNode node = head; node != null;) {
   ListNode next = node.getNext();
   node.setValue (null);
   node.setNext(null);
   node = next;
  }
  head = null;
  tail = null;
  size = 0;
 }
 public String toString() {
  ListNode node = head;
  String rst = "";
  while (node != null) {
   rst += String.valueOf(node.getValue());
   rst += " -> ";
   node = node.getNext();
  }
  return rst.substring(0, rst.length() - 4);
 }
 private ListNode getNode(int index) {
  int count = 0;
  if (index == size - 1)
   return tail;
  if (index == 0)
   return head;
  ListNode node = head;
  while (count < index && node != null) {
   node = node.getNext();
   count++;
  }
  return node;
 }
}





If you notice, this implementation actually can be used as a queue. However, since it is singly linked list, find any node in the list takes O(n) time.

Note that if a singly - linked list with only head pointer, it can be implemented as a stack.


(Singly) - Circular - Linked - List with a sentinel

The sentinel element is never used to hold data and it is always present. The principle is that it simplifies the programming of certain operations. E.g., we don't have to modify the head pointer. However, the disadvantage is that extra space is required.

One application for the circular linked list is to keep track of whose turn it is in a multi - player board game. Put all the players in a circular linked list, after the current player takes her turn, advance to the next player in the list. Break the cycle if the game is over.

Circular linked list can also be used as an implementation of queue. Here, we only need to maintain one pointer: the last inserted pointer. The first element is always the next of the last. Note this is also an FIFO container.

Moreover, when multiple applications are running on a PC, it is common for the OS to put the running applications on a list and then to cycle through them, giving each of them a slice of time to execute, and then making them wait while the CPU is given to another application. It is common to use a circular list so that when it reaches the end of the list, it can cycle around to the front of the list.

Note my implementation keeps track the element that has just been operated, so this cannot be used as an FIFO container.

/**
 * this class implements a circular singly linked list
 * since it's a circular list, there is no "head" and "tail"
 * a pointer points to the current location
 * any operation will set "current" to the node that has just been operated
 * Note this class does not include addLast() and removeLast() method
 * a "tail" pointer can be added to perform the these two operations
 * @author shirleyyoung
 *
 * @param 
 */
public class CircularSinglyLinkedList {
 private ListNode sentinel;
 private ListNode current;
 private long size;
 
 /**
  * construct a new list
  * current points to sentinel
  */
 public CircularSinglyLinkedList () {
  sentinel = new ListNode (null);
  //current = sentinel;
  //current.setNext(sentinel);
  clear();
  size = 0;
  //System.out.println("Construct an empty list!");
  //System.out.println(sentinel == null ? "sentinel equals null" : current.getValue());
 }
 public void clear() {
  sentinel.setNext(sentinel);
  current = sentinel;
  size = 0;
 }
 /**
  * insert an element after the current position
  * @param value
  * O(1)
  */
 public void add(T value) {
  ListNode node = new ListNode (value);
  //System.out.println(node.getValue());
  node.setNext(current.getNext());
  //System.out.println(node.getNext() == null ? "Null" : node.getNext().getValue());
  current.setNext(node);
  //System.out.println(current.getNext() == null ? "Null" : current.getNext().getValue());
  current = node;
  size++;
 }
 /**
  * add at desired position
  * @param index
  * @param value
  * O(n)
  */
 public void add(int index, T value) {
  if (index < 0 || index >= size)
   throw new IllegalArgumentException("Index must be greater than zero and less than list size!");
  if (index == 0)
   addFirst(value);
  int count = 0;
  ListNode node = sentinel.getNext();
  while (node != sentinel && count < index - 1) {
   node = node.getNext();
   count++;
  }
  ListNode toAdd = new ListNode (value);
  toAdd.setNext(node.getNext().getNext());
  node.setNext(toAdd);
  current = toAdd;
  size++;
 }
 /**
  * add at the head
  * O(1)
  * @param value
  */
 public void addFirst(T value) {
  current = sentinel;
  add(value);
  size++;
 }
 /**
  * remove the node at current position
  * makes its successor the current position
  * singly linked list, need to traverse the list
  * O(1)
  */
 public void remove() {
  if (sentinel.getNext() == sentinel) 
   throw new NullPointerException("Empty list!");
  ListNode node = sentinel;
  while (node.getNext() != current)
   node = node.getNext();
  node.setNext(current.getNext());
  current = current.getNext();
 }
 
 
 /**
  * if an object is in the list
  * Note it returns the first occurrence of the object
  * @param value
  * @return
  * O(n)
  */
 public boolean contains(T value) {
  //put the  value in sentinel, if the value cannot be 
  //found in the list, then the node will return to sentinel
  sentinel.setValue(value);
  ListNode node = sentinel.getNext();
  while (node.getValue() != value) 
   node = node.getNext();
  if (node == sentinel)
   return false;
  sentinel.setValue(null);
  //set current node to the desired node
  current = node;
  return true;
 }
 public boolean isEmpty() {
  return sentinel.getNext() == sentinel;
 }
 /**
  * return the current object
  * @return
  * O(1)
  */
 public T getCurrent() {
  if (current == sentinel)
   throw new NullPointerException("Empty list!");
  return current.getValue();
 }
 /**
  * get the first object in the list
  * makes the current be the head of the list
  * @return
  */
 public T getFirst() {
  current = sentinel.getNext();
  return getCurrent();
 }
 
 
 /**
  * set the value of the current element
  */
 public void setCurrent(T value) {
  if (current == sentinel)
   throw new NullPointerException("Empty list!");
  current.setValue(value);
 }
 /**
  * return the next object after the current element
  * @return
  */
 public T next() {
  if (!hasNext()) {
   System.err.println("No next element!");
   return null;
  }
  current = current.getNext();
  return current.getValue();
 }
 public boolean hasNext() {
  return current.getNext() != sentinel;
 }
 public String toString() {
  ListNode node = sentinel;
  //System.out.println(node == null ? "Null" : node.getValue());
  String rst = "";
  node = node.getNext();
  while (node != sentinel) {
   rst += String.valueOf(node.getValue());
   rst += " -> ";
   node = node.getNext();
  }
  return rst.substring(0, rst.length() - 4);
 }
}


Doubly - Linked -List

Java's LinkedList is a doubly linked list implementation. Doubly Linked list with both head and tail allows for add and remove from either head or tail in O(1) time, i.e., both queue and stack. However, if only head pointer is maintained, the list can be used as a stack.

Doubly linked list can be used to implement an LRU cache.



import java.util.NoSuchElementException;

public class DoublyLinkedList {
 int size;
 ListNode head;
 ListNode tail;
 public DoublyLinkedList () {
  head = null;
  tail = null;
  //head.next = tail;
  //tail.prev = head;
  size = 0;
 }
 /**
  * add at head
  * O(1)
  * @param obj
  */
 public void addFirst(T obj) {
  ListNode h = head;
  ListNode node = new ListNode (null, obj, h);
  head = node;
   if (tail == null)
    tail = node;
   else
    h.prev = node;
  size++;
 }
 /**
  * add at tail
  * O(1)
  * @param obj
  */
 public void addLast(T obj) {
  ListNode t = tail;
  ListNode node = new ListNode (t, obj, null);
  tail = node;
  if (head == null)
   head = node;
  else
   t.next = node;
  size++;
 }
 /**
  * insert at a desired position
  * O(n)
  */
 public void insert(int index, T obj) {
  isPositionIndex(index);
  if (index == 0) {
   addFirst(obj);
   return;
  }
  if (index == size) {
   addLast(obj);
   return;
  }
  ListNode prev = getNode(index - 1);
  ListNode curr = prev.next;
  ListNode toAdd = new ListNode(prev, obj, curr);
  curr.prev = toAdd;
  prev.next = toAdd;
  size++;
  
 }
 /**
  * remove first element in the list
  * O(1)
  * @return
  */
 public T removeFirst() {
  if (head == null)
   throw new NoSuchElementException("Probably empty list?");
  T obj = head.value;
  ListNode next = head.next;
  head.value = null;
  head.next = null;
  head = next;
  if (next == null)
   tail = null;
  else
   next.prev = null;
  size--;
  return obj;
 }
 /**
  * remove the last element
  * O(1) 
  * @return
  */
 public T removeLast() {
  if (tail == null)
   throw new NoSuchElementException("Probably empty list?");
  T obj = tail.value;
  ListNode prev = tail.prev;
  tail.value = null;
  tail.prev = null;
  tail = prev;
  if (prev == null)
   head = null;
  else 
   prev.next = null;
  size--;
  return obj;
 }
 /**
  * remove the element at given index
  * O(n)
  * @param index
  * @return
  */
 public T remove(int index) {
  isPositionIndex(index);
  if (index == size)
   throw new NoSuchElementException("Probably empty list?");
  if (index == 0) {
   return removeFirst();
  }
  if (index == size - 1) {
   return removeLast();
  }
  ListNode toRemove = getNode(index);
  T obj = toRemove.value;
  ListNode prev = toRemove.prev;
  ListNode next = toRemove.next;
  prev.next = next;
  next.prev = prev;
  toRemove.value = null;
  toRemove.prev = null;
  toRemove.next = null;
  size--;
  return obj;
  
 }
 
 public T getFirst() {
  if (head == null)
   throw new NoSuchElementException("Probably empty list?");
  return head.value;
 }
 public T getLast() {
  if (tail == null)
   throw new NoSuchElementException("Probably empty list?");
  return tail.value;
 }
 public int getSize() {
  return size;
 }
 public void clear() {
  for (ListNode node = head; node != null;) {
   ListNode next = node.next;
   node.value = null;
   node.next = null;
   node = next;
  }
  head = null;
  tail = null;
  size = 0;
 }
 public String toString() {
  ListNode node = head;
  String rst = "";
  while (node != null) {
   rst += String.valueOf(node.value);
   rst += " -> ";
   node = node.next;
  }
  return rst.substring(0, rst.length() - 4);
 }
 
 private ListNode getNode(int index) {
  //in the first half of the list
  //traverse from the head
  if (index < (size >> 1)) {
   ListNode node = head;
   for (int i = 0; i < index; i++)
    node = node.next;
   return node;
  }
  //in the second half
  //traverse from the tail
  else {
   ListNode node = tail;
   for (int i = size - 1; i > index; i--) {
    node = node.prev;
   }
   return node;
  }
 }
 private boolean isPositionIndex(int index) {
  if (index < 0 || index > size)
   throw new IndexOutOfBoundsException("Index must be greater than 0 and smaller than list size!");
  return true;
 }
 

}

Saturday, January 3, 2015

Reorder List

Given a singly linked list LL0L1→…→Ln-1Ln,
reorder it to: L0LnL1Ln-1L2Ln-2→…
You must do this in-place without altering the nodes' values.
For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.

The main purpose of this post is that I always have a problem with reverse linked list.

To reverse a list:
1. initialize a new node, newHead.
2. point the head to newHead.
3. let newHead be head.
4. go to the next node.

This is indeed an easy problem.

1. find middle node.
2. reverse the list.
3. merge the list.


public class ReorderList {
    public void reorderList(ListNode head) {
        if (head == null || head.next == null)
            return;
        ListNode mid = findMiddle(head);
        ListNode head2 = reverse(mid.next);
        mid.next = null;
        merge(head, head2);
        
    }
    private void merge(ListNode head, ListNode head2) {
        ListNode node = new ListNode(0);
        int index = 0;
        while (head != null && head2 != null) {
            if (index % 2 == 0) {
                node.next = head;
                head = head.next;
            }
            else {
                node.next = head2;
                head2 = head2.next;
            }
            node = node.next;
            index++;
        }
        if (head != null) 
            node.next = head;
        else
            node.next = head2;
    }
    private ListNode reverse(ListNode head) {
         ListNode newHead = null;
        while (head != null) {
            ListNode temp = head.next;
            head.next = newHead;
            newHead = head;
            head = temp;
        }
        return newHead;
    }
    private ListNode findMiddle(ListNode head) {
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

Saturday, December 20, 2014

Rotate List

Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
I thought this problem was pretty easy. But it took me more than 30 minutes to finish it. The problem is, I forgot n can be any length, so I need to let n = n % length first. Moreover, in the case where n == length, there is nothing to rotate and we simply return the head.




public class ListNode {
      int val;
      ListNode next;
      ListNode(int x) {
          val = x;
          next = null;
      }
  }
 
public class RotateList {
    public ListNode rotateRight(ListNode head, int n) {
        if (head == null || n <= 0)
            return head;
        ListNode dummy = new ListNode(0);
        int length = findLength(head);
        n = n % length;
        if (n == 0)
            return head;
        ListNode node = head;
        int index = 0;
        while (node != null && index < length - n - 1)
        {
            node = node.next;
            index++;
        }
        dummy.next = node.next;
        node.next = null;
        node = dummy.next;
        while(node.next != null)
            node = node.next;
        node.next = head;
        return dummy.next;
        
    }
    private int findLength(ListNode head)
    {
        int length = 0;
        while (head != null)
        {
            length++;
            head = head.next;
        }
        return length;
    }
}

Sunday, December 14, 2014

Insertion Sort List

"Sort a linked list using insertion sort."
3 -> 1 -> 12 -> 6

dummy(0) -> null
dummy(0) -> 3 -> null
dummy(0) -> 1 -> 3 -> null
dummy(0) -> 1 -> 3 -> 12 -> null
dummy(0) -> 1 -> 3 -> 6 -> 12 -> null


 
public class ListNode {
      int val;
      ListNode next;
      ListNode(int x) {
          val = x;
          next = null;
      }
  }
 
public class InsertionSort {
    public ListNode insertionSortList(ListNode head) {
        if (head == null)
            return null;
        ListNode dummy = new ListNode(0);
        while (head != null)
        {
            ListNode node = dummy;
            while (node.next != null && node.next.val < head.val)
                node = node.next;
            ListNode tmp = head.next;
            head.next = node.next;
            node.next = head;
            head = tmp;
        }
        return dummy.next;
    }
}

Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5


This problem is not a really "hard" one as long as you understand how to reverse lists, which I am always confused about. For that reason, I am posting a reverseList method for my reference.


        
ListNode reverseList(ListNode head)
{
    ListNode newhead = null;
    while (head != null)
    {
 ListNode tmp = head.next;
 head.next = newhead;
 newhead = head;
 head = tmp;
    }
    return new head;

}


1. We get the length of the list.
2. We divide the length by k, and get the number of "reverse" we need. Return boundary conditions.
3. We iterate to reverse the list k times. Remember to track the "tail" and "head" of each group to link them together.


public class ReverseList {
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null)
            return null;
        int length = 0;
        ListNode curr = head;
        while (curr != null)
        {
            length++;
            curr = curr.next;
        }
        //in the case where k is greater than the length of the lists, return
        int multi = length / k;
        if (k <= 1 || multi == 0)
            return head;
        ListNode curtail = null;
        ListNode curhead = null;
        ListNode pretail = null;
        curr = head;
        for (int i = 0; i < multi; i++)
        {
            ListNode preNode = null;
            ListNode nextNode = null;
            for (int j = 0; j < k; j++)
            {
                nextNode = curr.next;
                curr.next = preNode;
                preNode = curr;
                if (j == 0) curtail = curr;
                if (j == k - 1) curhead = curr;
                curr = nextNode;
            }
            if (pretail != null)
                pretail.next = curhead;
            else
                head = curhead;
            pretail = curtail;
        }
        //if there are left-out nodes, current tail points to the next node
        // otherwise points to null
        curtail.next = curr;
        return head;
    }
}

Merge k sorted lists

"Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity."

Using a PriorityQueue is a very smart way. The time complexity is n* O(log(lists.size())) where n is the total nodes in all linked lists.


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

public class MergeLists {
    public ListNode mergeKLists(List<ListNode> lists) {
        if (lists == null || lists.size() == 0)
            return null;
        PriorityQueue<ListNode> listNodeQueue = new PriorityQueue<ListNode> (lists.size(), new ListNodeComparator());
        for (ListNode node : lists) {
            if (node != null)
                listNodeQueue.add(node);
        }
        ListNode dummy = new ListNode(0);
        ListNode head = dummy;
        while (!listNodeQueue.isEmpty()) {
            ListNode toAdd = listNodeQueue.poll();
            head.next = toAdd;
            if (toAdd.next != null)
                listNodeQueue.add(toAdd.next);
            head = head.next;
        }
        return dummy.next;
        
    }
    private class ListNodeComparator implements Comparator<ListNode> {
        public int compare (ListNode a, ListNode b) {
            return a.val - b.val;
        }
    }
}

Thursday, December 11, 2014

Linked List Cycle

Let's start with the easy one.

O - O - O - ... O -  P
                           /     \
                         P        P
                        /            \
                       P - P ... - P

Not a very beautiful cycle, but we can still get by with it. 
If we only want to find if there is a cycle, traverse the list with a fast node and a slow node. The fast node goes two steps at a time while the slow one only move one step. If there is a cycle, at the end of the day, they will meet, happy ending! 

class ListNode {
      int val;
      ListNode next;
      ListNode(int x) {
          val = x;
          next = null;
      }
  }
public class ListCycle {
    public boolean hasCycle(ListNode head) {
        if (head == null)
            return false;
        ListNode fast = head.next;
        ListNode slow = head;
        while (fast != null && fast.next != null)
        {
            if (fast == slow)
                return true;
            fast = fast.next.next;
            slow = slow.next;
        }
        return false;
        
    }
}

Now here is the problem, what if we need to find where the cycle begins? By using the former method, it is highly possible that the two nodes meet inside the cycle, so what to do next?
Let's review a little bit math.
Let X be the number of nodes outside the cycle (assume there is one), so X = number of all the O's in the graph.
Let Y be the number of nodes inside the cycle, so Y = number of all the P's (why did I use P not C? -_-|||).
Let m be the node at which fast and slow meet, let s be the start point of the cycle, then let K = m - s + 1, which is the number of nodes from the beginning of the cycle to the meeting point. Let steps be number of steps each node traverses before they meet.
fast: X + mY + K = 2steps  (1)

slow: X + nY + K = steps    (2)
substitute (2) to (1), and we have
X = (m - 2n)Y - K
since Y is a cycle, m, n can be any integer, let m - 2n = 1

X = Y - K, which means, after two nodes meet, the number of steps the slow node need to traverse before return to the start point of the cycle equals number of nodes outside the cycle. This means we can let the head do some exercise with the slow node and, problem solved!

Update: 2015 - 01- 03

1. Be sure to initialize both slow and fast node at the head. If the fast starts at head.next, the meeting point will be different. In that case, let slow go one further node after exiting the loop.
2. check the equivalence between slow and head before move to the next node.

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

Intersection of Two Linked Lists

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists: 
A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3
begin to intersect at node c1.

Notes:
  • If the two linked lists have no intersection at all, return null.
  • The linked lists must retain their original structure after the function returns. 
  • You may assume there are no cycles anywhere in the entire linked structure.
  • Your code should preferably run in O(n) time and use only O(1) memory.

A fresh new problem. Somehow I am very in to linked list. I think I am just having fun play around with pointers. 

Back to the problem. I found this method through GeeksforGeeks, and implemented it using Java. Consider I am such a fake one, I have no guilty borrowing it. 

1. Determine the size of both linked lists.  
2. Get the difference between two lists diff = abs(sizeA - sizeB). 
3. Traverse the list with the larger size until node diff. 
4. Traverse both lists together, if both the value and pointer of the nodes are the same in two lists, we can conclude they intersect. Otherwise, if nothing pops up till the end of both lists, return null. 

Mission accomplished. :)

public class ListNode {
      int val;
      ListNode next;
      ListNode(int x) {
          val = x;
          next = null;
      }
  }
 
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null)
            return null;
        int sizeA = getSize(headA);
        int sizeB = getSize(headB);
        int diff = Math.abs(sizeA - sizeB);
        int index = 0;
        if (sizeA > sizeB)
        {
            while (headA != null && index < diff)
            {
                headA = headA.next;
                index++;
            }
        }
        else
        {
            while(headB != null && index < diff)
            {
                headB = headB.next;
                index++;
            }
        }
        while (headA != null && headB != null)
        {
            if (headA.val == headB.val && headA.next == headB.next)
                return headA;
            headA = headA.next;
            headB = headB.next;
        }
        return null;
        
        
    }
    private int getSize(ListNode head)
    {
        int size = 0;
        while (head != null)
        {
            size++;
            head = head.next;
        }
        return size;
    }
}

Sunday, September 14, 2014

Reverse Linked List

Reverse a linked list from position m to n. Do it in-place and in one-pass.
For example: Given 1->2->3->4->5->NULLm = 2 and n = 4,
return 1->4->3->2->5->NULL.
Note: Given mn satisfy the following condition: 1 ≤ m ≤ n ≤ length of list.
Label the m-th node(label) and the node before m-th node (prelabel). Insert nodes afterwards till the n-th node one by one between prelabel and label. 

prelabel: 1
label: 2
1 -> 3 -> 2 -> 4 -> 5
1 -> 4 -> 3 -> 2 -> 5

public class ListNode {
      int val;
      ListNode next;
      ListNode(int x) {
          val = x;
          next = null;
      }
  }
public class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if (head == null)
            return null;
        if (m == n)
            return head;
            
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        int index = 1;
        ListNode prelabel = dummy;
        for (index = 1; index < m; index++)
        {
            prelabel = head;
            head = head.next;
            if (head == null)
                return null;
        }
        ListNode prev = head;
        ListNode label = head;
        head = head.next;
        //index ++;
        for (index = m + 1; index <= n; index++)
        {
            label.next = head.next;
            prelabel.next = head;
            head.next = prev;
            prev = head;
            head = label.next;
        }
        return dummy.next;
    }
}