Wednesday, October 4, 2017

Word Search

Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
For example,
Given board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.


/* method 1: 
 * time:O(m*n*4^L), space:O(m*n), m: board's row, n: board's column, L: word size
 * Imagine this is a tree,  this quadtree's height is L(L is length of word) and its total node number is
 * 4^0 + 4^1 + ... + 4^L = 1/3 * ( 4^(L+1) - 1 ). So the time complexity of this dfs solution is  * mnO(4^L).
 */
public class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        int width = board.length;
        int length = board[0].length;
        boolean[][] visited = new boolean[width][length];
        for (int y = 0; y < width; y++) {
        for (int x = 0; x < length; x++) {
        if (exist(board, y, x, words, 0, visited)) {
                                return true;
                        }
        }
        }
        return false;
    }
    
    private boolean exist(char[][] board, int y, int x, char[] words, int i, boolean[][] visited) {
    if (i == words.length) {
            return true;
        }
    if (y < 0 || x < 0 || y == board.length || x == board[y].length || visited[y][x] == true) {
            return false;
        }
    if (board[y][x] != words[i]) {
            return false;
        }
    visited[y][x] = true;
    boolean exist = exist(board, y, x + 1, words, i + 1, visited)
               || exist(board, y, x - 1, words, i + 1, visited)
               || exist(board, y + 1, x, words, i + 1, visited)
               || exist(board, y - 1, x, words, i + 1, visited);
    visited[y][x] = false;
    return exist;
    }

}



/* method2:
 time:O(m*n*4^L), space:O(1)
 *
 * board[y][x] ^= 256 it's a marker that the letter at position x,y is a part of word we search.
 * After board[y][x] ^= 256 the char became not a valid letter. After second board[y][x] ^= 256
 * it became a valid letter again.
 */

public class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        int row = board.length;
        int column = board[0].length;
        for (int y = 0; y < row; y++) {
         for (int x = 0; x < column; x++) {
         if (exist(board, y, x, words, 0)) {
                              return true;
                        }
         }
        }
        return false;
    }
    
    private boolean exist(char[][] board, int y, int x, char[] words, int i) {
     if (i == words.length) {
            return true;
        }
     if (y < 0 || x < 0 || y == board.length || x == board[y].length) {
            return false;
        }
     if (board[y][x] != words[i]) {
            return false;
        }
     board[y][x] ^= 256;
     boolean exist = exist(board, y, x + 1, words, i + 1)
                 || exist(board, y, x - 1, words, i + 1)
                 || exist(board, y + 1, x, words, i + 1)
                 || exist(board, y - 1, x, words, i + 1);
     board[y][x] ^= 256;
     return exist;
    }

}

Monday, October 2, 2017

K closest points

/*
 * Find the K closest points to the origin in 2D plane, given an array containing N points.
 * You can assume K is much smaller than N and N is very large.
 * You need only use standard math operators (addition, subtraction, multiplication, and division).
 */
import java.util.*;

class Point {
    double x;
    double y;
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}
public class Solution {
private static double distance(Point a, Point b) {
        return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
    }
public static Point[] closestPoint(Point[] array, final Point origin, int k) {
        if (k >= array.length) {
        // return array;
        k = array.length;
        }
        if (k <= 0) {
        return new Point[0];
        }
        Point[] res = new Point[k];
        PriorityQueue<Point> maxHeap = new PriorityQueue<>(k + 1, new Comparator<Point>() {
            @Override
            public int compare(Point a, Point b) {
                return Double.compare(distance(b, origin), distance(a, origin));
            }
        });
        for(Point p : array) {
        maxHeap.offer(p);
        if (maxHeap.size() > k) {
        maxHeap.poll();
        }
        }
        for(int i = k - 1; i >= 0; i--) {
        res[i] = maxHeap.poll();
        }
        return res;
    }

    public static void main(String[] args) {
        Point origin = new Point(0, 0);
        Point[] input = new Point[]{new Point(0, 2), new Point(1, 1), new Point(-1, 0), new Point(2, 0), new Point(3, 0)};
        Point[] output = closestPoint(input, origin, 3);
        System.out.println("input");
        for(Point i : input) System.out.print("("+i.x+", "+i.y+") ");
        System.out.println("");
        System.out.println("output");
        for(Point i : output) System.out.print("("+i.x+", "+i.y+") ");
    }
}

Monday, May 1, 2017

Implement a fix-sized queue using array

Implement a fix-sized queue using array.


import java.util.*;

public class Queue<T> {
private int front;
private int rear;
private int size;
private final T[] queue;

public Queue(int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException("Size cannot be less than or equal to zero.");
}
size = 0;
front = 0;
rear = -1;
queue = (T[])new Object[capacity];
}

public int size() {
return size;
}

public void enQueue(T item) {
if (size == queue.length) {
throw new IllegalStateException("Queue is full.");
}
rear = (rear + 1) % queue.length;
queue[rear] = item;
size++;
}

public T deQueue() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty.");
}
T value = queue[front];
front = (front + 1) % queue.length;
size--;
return value;
}

public boolean isEmpty() {
return size == 0;
}

public T peek() {
if (isEmpty()) {
throw new IllegalStateException("Queue is Empty.");
}
return queue[front];
}

@Override
public String toString() {
int s = size;
int head = front;
String str = "[";
while (s > 1) {
str += queue[head];
str += ", ";
s--;
head = (head + 1) % queue.length;
}
if (s == 1) {
str += queue[head];
}
str += "]";
return str;
}

    public static void main(String[] args) {
        Queue<Integer> newQueue = new Queue<>(5);
        newQueue.enQueue(10);
        newQueue.enQueue(20);
        newQueue.enQueue(30);
        newQueue.enQueue(40);
        newQueue.enQueue(50);
        System.out.println(newQueue.toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.toString());
        newQueue.enQueue(60);
        newQueue.enQueue(70);
        System.out.println("Size should be 5, the result is " + newQueue.size());
        System.out.println("Should be false, the result is " + newQueue.isEmpty());
        System.out.println(newQueue.toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.deQueue().toString());
        System.out.println(newQueue.toString());
        System.out.println("Size should be 0, the result is " + newQueue.size());
        System.out.println("Should be true, the result is " + newQueue.isEmpty());
    }
}

Thursday, March 23, 2017

Roman to Integer

/*
Given a roman numeral, convert it to an integer.
Input is guaranteed to be within the range from 1 to 3999.
*/

//time: O(n), space:O(1)
public class Solution {
    public int romanToInt(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        Map<Character, Integer> map = new HashMap<>();
        map.put('I', 1);
        map.put('V', 5);
        map.put('X', 10);
        map.put('L', 50);
        map.put('C', 100);
        map.put('D', 500);
        map.put('M', 1000);
        int res = map.get(s.charAt(s.length() - 1));
        for (int i = s.length() - 2; i >= 0; i--) {
            if (map.get(s.charAt(i)) >= map.get(s.charAt(i + 1))) {
                res += map.get(s.charAt(i));
            } else {
                res -= map.get(s.charAt(i));
            }
        }
        return res;
    }
}

Thursday, January 19, 2017

Subsets

Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

//DFS, time:O(n^2), space:O(1)
public class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return ans;
        }
        subsetsHelper(nums, ans, new ArrayList<Integer>(), 0);
        return ans;
    }
    public void subsetsHelper(int[] nums, List<List<Integer>> ans,                                 List<Integer> list, int start) {
        ans.add(new ArrayList<Integer>(list));
        for (int i = start; i < nums.length; i++) {
            list.add(nums[i]);
            subsetsHelper(nums, ans, list, i + 1);
            list.remove(list.size() - 1);
        }
    }
}


/*
bfs:
First, adding an empty list to the ans, then iterate the input array, each time adding the number to all the existed subsets. The new subsets and the previous subsets together make up the new ans. 

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

public class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return ans;
        }
        List<Integer> list = new ArrayList<>();
        ans.add(list);
        for (int i = 0; i < nums.length; i++) {
            int size = ans.size();
            for (int j = 0; j < size; j++) {
                list = new ArrayList<>(ans.get(j));
                list.add(nums[i]);
                ans.add(list);
            }
        }
        return ans;
    }
}

Sort Colors

Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note:
You are not suppose to use the library's sort function for this problem.

/*
A rather straight forward solution is a two-pass algorithm using counting sort. First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.

Also, we can use three pointers with one pass solution. In each step during the iteration, we do either of three things. Swap with the left, swap with the right, or move forward.

time:O(n), space:O(1)
*/
public class Solution {
    public void sortColors(int[] nums) {
        if (nums == null || nums.length == 0) {
            return;
        }
        int left = 0;
        int right = nums.length - 1;
        int i = 0;
        while (i <= right) {
            if (nums[i] == 1) {
                i++;
            } else if (nums[i] == 0) {
                swap(nums, left, i); 
                left++;
                i++;
            } else {
                swap(nums, right, i);
                right--;
            }
        }
    }
    public void swap(int[] nums, int a, int b) {
        int tmp = nums[a];
        nums[a] = nums[b];
        nums[b] = tmp;
    }
}

Clone Graph

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.

OJ's undirected graph serialization:
Nodes are labeled uniquely.
We use # as a separator for each node, and , as a separator for node label and each neighbor of the node.
As an example, consider the serialized graph {0,1,2#1,2#2,2}.
The graph has a total of three nodes, and therefore contains three parts as separated by #.
  1. First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
  2. Second node is labeled as 1. Connect node 1 to node 2.
  3. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.
Visually, the graph looks like the following:
       1
      / \
     /   \
    0 --- 2
         / \
         \_/

/**
 * Definition for undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     List<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { 
 *        label = x; 
 *        neighbors = new ArrayList<UndirectedGraphNode>(); 
 *     }
 * };
 */

/*
Use Queue to implement BFS and use HashMap to deep clone every graph node and connect their neighbors.

time:O(V+E), space:O(V), E is the number of neighbors, V is the number of nodes.
*/

public class Solution {
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        if (node == null) {
            return null;
        }
        Queue<UndirectedGraphNode> queue = new LinkedList<>();
        Map<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<>();
        queue.offer(node);
        map.put(node, new UndirectedGraphNode(node.label));
        while (!queue.isEmpty()) {
            UndirectedGraphNode curr = queue.poll();
            for (UndirectedGraphNode neighbor : curr.neighbors) {
                if (!map.containsKey(neighbor)) {
                    queue.offer(neighbor);
                    map.put(neighbor, new UndirectedGraphNode(neighbor.label));
                }
                map.get(curr).neighbors.add(map.get(neighbor));
            }
        }
        return map.get(node);
    }
}


//DFS, time:O(V+E), space:O(V)
public class Solution {
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        Map<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<>();
        return deepClone(map, node);
    }
    public UndirectedGraphNode deepClone(Map<UndirectedGraphNode,                                              UndirectedGraphNode> map, UndirectedGraphNode node) {
        if (node == null) {
            return null;
        }
        if (map.containsKey(node)) {
            return map.get(node);
        }
        map.put(node, new UndirectedGraphNode(node.label)); 
        for (UndirectedGraphNode neighbor : node.neighbors) {
            map.get(node).neighbors.add(deepClone(map, neighbor));
        }
        return map.get(node);
    }

}