Fibonacci Number


public class Fib {
	
	/*
	 * recursion O(2^N)
	 */
	public static int fib(int n){
		if(n < 0){
			throw new IllegalArgumentException();
		}
		if(n == 0) return 0;
		if(n == 1) return 1;
		return fib(n - 1) + fib(n - 2);
	}
	
	/*
	 * DP O(n) time and space complexity 
	 */
	public static int fib2(int n){
		if(n < 0){
			throw new IllegalArgumentException();
		}
		if(n == 0) return 0;
		if(n == 1) return 1;
		
		int[] states = new int[n + 1];
		states[0] = 0;
		states[1] = 1;
		for(int i = 2; i <=n; i++){
			states[i] = states[i - 1] + states[i - 2];
		}
		return states[n];
	}
	
	/*
	 * Optimized DP O(n) time and O(1) space complexity 
	 */
	public static int fib3(int n){
		if(n < 0){
			throw new IllegalArgumentException();
		}
		if(n == 0) return 0;
		if(n == 1) return 1;
		
		int num1 = 0, num2 = 1, res = 0;
		for(int i = 2; i <= n; i++){
			res = num1 + num2;
			num1 = num2;
			num2 = res;
		}
		return res;
	}
	
	/*
	 * [1 1]  [Fn+1 Fn]
	 * [1 0]  [Fn   Fn -1]
	 * O(logn)
	 */
	public static int fib4(int n){
		if(n < 0){
			throw new IllegalArgumentException();
		}
		if(n == 0) return 0;
		if(n == 1) return 1;
		
		int[][] matrix = {{1, 1}, {1, 0}};
		pow(matrix, n - 1);
		return matrix[0][0];
	}
	
	private static void pow(int[][] matrix, int n){
		if(n == 0 || n == 1){
			return;
		}
		pow(matrix, n / 2);
		multiply(matrix, matrix);
		if(n % 2 != 0){
			int[][] temp = {{1, 1}, {1, 0}};
			multiply(matrix, temp);
		}
	}
	
	private static void multiply(int[][] matrix, int[][] base){
		int x = matrix[0][0] * base[0][0] + matrix[0][1] * base[1][0];
		int y = matrix[0][0] * base[0][1] + matrix[0][1] * base[1][1];
		int z = matrix[1][0] * base[0][0] + matrix[1][1] * base[1][0];
		int k = matrix[1][0] * base[0][1] + matrix[1][1] * base[1][1];
		matrix[0][0] = x;
		matrix[0][1] = y;
		matrix[1][0] = z;
		matrix[1][1] = k;
	}
	
	
	public static void main(String[] args){
		for(int i = 0; i <= 20; i++){
			System.out.println(fib(i) + " " + fib2(i) + " " + fib3(i) + " " + fib4(i));
			
		}
	}
	
	

}

Reservior Sample

import java.util.*;
public class ReserviorSample {
	
	/*
	 * warm up
	 * knuth shuffle
	 */
	public static void shuffle(int[] num){
		if(num == null || num.length == 0){
			return;
		}
		Random rnd = new Random();
		int N = num.length;
		for(int i = 0; i < N; i++){
			int idx = i + rnd.nextInt(N - i);
			swap(num, i, idx);
		}
		
	}
	
	/*
	 * Say you have a stream of items of large and unknown length that we can only iterate over once. 
	 * Create an algorithm that randomly chooses an item from this stream such that each item is 
	 * equally likely to be selected
	 */
	public static int sample(Iterator<Integer> it){
		if(it == null || !it.hasNext()){
			throw new IllegalArgumentException(" ");
		}
		Random rnd = new Random();
		int n = 0, sample = 1;
		while(it.hasNext()){
			n++;
			int num = it.next();
			if(n == 1){
				sample = num;
			}else{
				int idx = rnd.nextInt(n);
				if(idx == 0){
					sample = num;
				}
			}
		}
		return sample;
	}
	
	/*
	 * Reservoir sampling is a family of randomized algorithms for randomly choosing k 
	 * samples from a list of n items, where n is either a very large or unknown number
	 */
	public static int[] reservoirSample(Iterator<Integer> it, int k){
		if(it == null || !it.hasNext() || k <= 0){
			return null;
		}
		Random rnd = new Random();
		int[] res = new int[k];
		int i = 0;
		while(it.hasNext()){
			int num = it.next();
			if(i < k){
				res[i] = num;
			}else{
				int idx = rnd.nextInt(i + 1);
				if(idx < k){
					res[idx] = num;
				}
			}
			i++;
		}
		if(i < k) throw new RuntimeException();
		return res;
	}
	
	private static void swap(int[] nums, int i, int j){
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
	
	public static void main(String[] args){
		int[] nums = {1, 2, 3, 4, 5};
		shuffle(nums);
		for(int i : nums){
			//System.out.println(i);
		}
		ArrayList<Integer> res = new ArrayList<Integer>();
		for(int i = 1; i <= 10; i++){
			res.add(i);
		}
		int[] dist = new int[11];
		for(int i = 0; i < 1000; i++){
			int num = sample(res.iterator());
			dist[num]++;
		}
		for(int i = 1; i < dist.length; i++){
			System.out.println("num " + i + " produce " + dist[i] + " times");
		}
		int[] sams = reservoirSample(res.iterator(), 5);
		for(int i : sams) System.out.print(i + " ");
		
	}

}

Find Missing number

1, 1 – N missing 一个数
如果sorted, 用二分法,找到第一个a[i] != i + 1的地方
如果不sorted, 用通项公式求等差序列和 – sum of array
或者XOR (a1^a2^a3) ^ (a1^a2) = a^3
2, 如果missing两个数
解二元一次方程 x + y = num1
x^2 + y^2 = num2
3, 如果missing K个数
array sorted, 直接linear scan
not sorted http://stackoverflow.com/questions/3492302/easy-interview-question-got-harder-given-numbers-1-100-find-the-missing-numbe

/*
 * 给一个sorted array, 这个array的size是N-K
原本这个array应该是有从1-N,N个数 但是miss了K个
请找出这miss的K个数
 */
public class FindMissingNumber {
	
	public static int[] findMissing(int[] nums, int N){
		if(nums == null || nums.length < 0 || N < 0){
			return null;
		}
		int[] res = new int[N - nums.length];
		int idx = 0;
		//front
		if(nums[0] != 1){
			int counter = 1;
			while(counter < nums[0]){
				res[idx++] = counter++;
			}
		}
		//middle
		for(int i = 0; i < nums.length - 1; i++){
			if(nums[i] != nums[i + 1] - 1){
				int counter = nums[i] + 1;
				while(counter < nums[i + 1]){
					res[idx++] = counter++;
				}
			}
		}
		//end
		if(nums[nums.length - 1] < N){
			int counter = nums[nums.length - 1];
			while(counter < N){
				res[idx++] = counter++;
			}
		}
		return res;
	}
	
	public static void main(String[] args){
		int[] nums = {3, 4, 6, 7, 9, 10};
		int[] res = findMissing(nums, 10);
		for(int i : res) System.out.print(i + " ");
	}

}

Robot Variant

/*
 * 机器人走格子,要求生成所有路线,而不只是单纯的总方法数。改下返回的结果和递归时的传参
 */
import java.util.*;
public class Robot {
	
	private class Pos{
		int x;
		int y;
		public Pos(int x, int y){
			this.x = x;
			this.y = y;
		}
		
		public String toString(){
			return "( " + x + " " + y +  " )"; 
		}
	}
	
	public List<List<Pos>> path(int[][] matrix){
		List<List<Pos>> res = new ArrayList<List<Pos>>();
		if(matrix == null || matrix.length == 0){
			return res;
		}
		ArrayList<Pos> path = new ArrayList<Pos>();
		dfs(res, path, matrix, 0, 0);
		return res;
	}
	
	private void dfs(List<List<Pos>> res, ArrayList<Pos> path, int[][] matrix, int x, int y){
		int m = matrix.length, n = matrix[0].length;
		if(x == m - 1 && y == n - 1){
			path.add(new Pos(x, y));
			res.add(new ArrayList<Pos>(path));
			path.remove(path.size() - 1);
			return;
		}
		if(x < 0 || x > m || y < 0 || y > n) return;
		path.add(new Pos(x, y));
		dfs(res, path, matrix, x + 1, y);
		dfs(res, path, matrix, x, y + 1);
		path.remove(path.size() - 1);
	}
	
	public static void main(String[] args){
		int[][] nums = {{1, 1, 1}};
		System.out.println(new Robot().path(nums));
	}

}

Longest Arithmetic Progression

//reference http://www.geeksforgeeks.org/length-of-the-longest-arithmatic-progression-in-a-sorted-array/

import java.util.*;
public class LongestArithmeticProgression {
	
	/*
	 * warm up
	 * This function returns true if there exist three elements in AP
	 * Assumption: array is sorted
	 * 等差序列性质 a[n - 1] + a[n + 1] = 2a[n]
	 * 我们变量一边数组a[i]设为中间值,a[i - 1] 为第一个, a[i + 1]为第三个
	 * 就变成2sum了,如果和小,增加右边的pointer,和大,减少左边的pointer
	 */
	public static boolean ap3(int[] nums){
		for(int i = 1; i < nums.length - 1; i++){
			int left = i - 1, right = i + 1;
			while(left >= 0 && right < nums.length){
				int sum = nums[left] + nums[right];
				if(sum == 2 * nums[i]) return true;
				else if(sum < 2 * nums[i]) right++;
				else left++;
			}
		}
		return false;
	}
	
	public static int llap(int[] nums){
		if(nums == null){
			return 0;
		}
		if(nums.length <= 2){
			return nums.length;
		}
		int n = nums.length, max = 2;
		//状态为以a[i]. a[j]为前两个元素的等差序列的长度,j > i
		int[][] states = new int[n][n];
		//初始化
		for(int i = 0; i < n; i++){
			states[i][n - 1] = 2;
		}
		for(int j = n - 2; j >= 1; j--){
			int i = j - 1, k = j + 1;
			while(i >= 0 && k < n){
				int sum = nums[i] + nums[k];
				if(sum < 2 * nums[j]) k++;
				else if(sum > 2 * nums[j]){
					states[i][j] = 2;
					i--;
				}else{
					//System.out.println(nums[i] + " " + nums[j] + " " + nums[k]);
					states[i][j] = states[j][k] + 1;
					max = Math.max(max, states[i][j]);
					i--;
					k++;
					
				}
			}
			while(i >= 0){
				states[i][j] = 2;
				i--;
			}
		}
		return max;
	}
	
	/*
	 * brute-force O(N^3)
	 */
	public static int llapBF(int[] nums){
		if(nums == null) return 0;
		if(nums.length <= 2) return nums.length;
		int max = 2;
		Arrays.sort(nums);
		/*
		 * a[i], a[j]为等差序列的前两项 N^2 pair
		 * 每一次去找下一个 N
		 * TOTAL O(n^3)
		 */
		int n = nums.length;
		for(int i = 0; i < n; i++){
			for(int j = i + 1; j < n; j++){
				int counter = 2;
				int diff = nums[j] - nums[i];
				int target = nums[j] + diff;
				for(int k = j + 1; k < n; k++){
					if(target == nums[k]){
						counter++;
						target = nums[k] + diff;
					}
				}
				max = Math.max(max, counter);
			}
		}
		return max;
	}
	
	public static void main(String[] args){
		int[] nums = {1, 7, 10, 13, 14, 19};
		System.out.println(llapBF(nums));
		int[] nums1 = {2, 4, 6, 8, 10};
		System.out.println(llapBF(nums1));
		int[] nums2 = {1, 7, 10, 15, 27, 29};
		System.out.println(llapBF(nums2));
	}
	
	

}

Shortest unique prefix to represent word in an array

看到prefix肯定想到的是trie咯,在trie node里面多加一个field count,表示
这个字符出现多少次
1,insert word into the trie
2, search the word, 找到第一个count为1的node,返回
因为说明这个node下面没有分支了,他就应该是唯一的

/*
 * 求一个string list的每个string对应的unique prefix,返回也是一个list
 */
public class TriePrefix {
	
	public static final int R = 256;
	private Node root;
	
	private class Node{
		private int count;
		private boolean isEnd;
		private Node next[] = new Node[R];
		
		public Node(){
			count = 0;
			isEnd = false;
		}

		public Node(int count, boolean isEnd){
			this.count = count;
			this.isEnd = isEnd;
		}
	}
	
	public void insert(String str){
		if(root == null) root = new Node();
		Node curr = root;
		for(int i = 0; i < str.length(); i++){
			char c = str.charAt(i);
			if(curr.next[c] == null){
				curr.next[c] = new Node(1, false);
			}else{
				curr.next[c].count++;
			}
			curr = curr.next[c];
		}
		curr.isEnd = true;
	}
	
	public String shortestPrefix(String str){
		Node curr = root;
		int len = 0;
		for(int i = 0; i < str.length(); i++){
			char c = str.charAt(i);
			curr = curr.next[c];
			len++;
			if(curr.count == 1) break;
		}
		return str.substring(0, len);
	}
	
	public static void main(String[] args){
		TriePrefix trie = new TriePrefix();
		String[] words = {"by", "sea", "sells", "she", "shells", "shore", "the"};
		String[] words1 = {"zebra", "dog", "duck", "dove"};
		for(String word : words1){
			trie.insert(word);
		}
		String[] res = new String[words1.length];
		for(int i = 0; i < words1.length; i++){
			res[i] = trie.shortestPrefix(words1[i]);
			System.out.println(res[i]);
		}
	}

}

Port

需要实现一个routetable,ip的前缀 -> port number,有插入和查找两个操作。其中ip和ip前缀都是二进制,由vector表示。查找返回routetable中和ip最长匹配的前缀所对应的portnumber,如果没有前缀匹配,返回-1。
给定API. 1point 3acres 璁哄潧
void insert (vector prefix, int port);
void find (vector ip);

其实就是R = 2 的TRIE, 因为只有0,1两种


public class Port {
	
	private class Node{
		int port;
		Node left;
		Node right;
		
		public Node(int port){
			this.port = port;
		}
	}
	
	private Node root = new Node(-1);
	
	public void insert(int[] prefix, int port){
		Node node = root;
		for(int i = 0; i < prefix.length; i++){
			if(prefix[i] == 0){
				if(node.left == null){
					node.left = new Node(-1);
				}
				node = node.left;
			}else{
				if(node.right == null){
					node.right = new Node(-1);
				}
				node = node.right;
			}
		}
		node.port = port;
	}
	
	public int find(int[] ip){
		if(ip == null) return -1;
		Node node = root;
		for(int i = 0; i < ip.length; i++){
			if(ip[i] == 0){
				if(node.left == null) return -1;
				else node = node.left;
			}else{
				if(node.right == null) return -1;
				else node = node.right;
			}
		}
		return node.port;
	}
	
	public static void main(String[] args){
		Port p = new Port();
		int[] ip1 = {1, 0, 1, 0, 1, 0};
		p.insert(ip1, 10);
		System.out.println(p.find(ip1));
		int[] ip2 = {1, 0, 1, 0, 1};
		System.out.println(p.find(ip2));
		
	}

}

sum of 3 smallest number

一个数组中最小的三个的和, 用三个变量记录最小的三个就好了,处理数组长度小于3的情况


import java.util.*;
public class Solution {
    /**
     * @param lists: a list of ListNode
     * @return: The head of one sorted list.
     */
    public static int smallest3(int[] nums){
        if(nums == null || nums.length &lt; 3){
            throw new IllegalArgumentException();
        }
        int min = Integer.MAX_VALUE, second = min, third = min;
        for(int num : nums){
            if(num &lt; min){
                third = second;
                second = min;
                min = num;
            }else if(num &lt; second){
                third = second;
                second = num;
            }else if(num &lt; third){
                third = num;
            }
        }
        return min + second + third;
    }
    
    public static void main(String[] args){
        int[] nums = {-1, -2, -3, -4, -5, -6};
        System.out.println(smallest3(nums));
        
    }
}


Most Frequent Char

给一个字符串,找打至少出现N次的char,按大小顺序输出

/**
 * Definition for ListNode.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int val) {
 *         this.val = val;
 *         this.next = null;
 *     }
 * }
 */ 
import java.util.*;
public class Solution {
    /**
     * @param lists: a list of ListNode
     * @return: The head of one sorted list.
     */
    public static String mostFreq(String str, int N){
        if(str == null || str.length() == 0){
            return str;
        }
        TreeMap treemap = new TreeMap();
        for(int i = 0; i &lt; str.length(); i++){
            char c = str.charAt(i);
            if(c  'z') continue;
            if(!treemap.containsKey(c)){
                treemap.put(c, 1);
            }else{
                treemap.put(c, treemap.get(c) + 1);
            }
        }
        StringBuilder sb = new StringBuilder();
        for(char c : treemap.keySet()){
            if(treemap.get(c) &gt;= N){
                sb.append(c);
            }
        }
        return sb.toString();
        
    }
    
    public static void main(String[] args){
        String s = "today is that saturday";
        System.out.println(mostFreq(s, 3));
    }
}

Duplicates 123

import java.util.*;
public class Solution{
    
    
    /*
     * Write a function that is given an array of integers. It should return true if
     * any value appears at least twice in the array, and it should return false if
     * every element is distinct
     */
    public static boolean containsDuplicate(int[] arr) {
        if(arr == null || arr.length == 0){
            return true;
        }
        HashSet<Integer> hashset = new HashSet<Integer>();
        for(int num : arr){
            if(hashset.contains(num)){
                return true;
            }
            hashset.add(num);
        }
        return false;
    }
    
    /**
     * Write a function that is given an array of integers and an integer k. It
     * should return true if and only if there are two distinct indices i and j into
     * the array such that arr[i] = arr[j] and the difference between i and j is at
     * most k.
     */     
    public static boolean containsNearbyDuplicate(int[] arr, int k) {
        if(arr == null || arr.length == 0 || k < 1){
            return false;
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        HashSet<Integer> hashset = new HashSet<Integer>();
        for(int i = 0; i < arr.length; i++){
            int num = arr[i];
            if(hashset.contains(num)){
                return true;
            }
            hashset.add(num);
            queue.offer(num);
            if(hashset.size() > k){
                hashset.remove(queue.poll());
            }
        }
        return false;
    }
    
     /** 
     * Write a function that is given an array of integers. It should return true if
     * and only if there are two distinct indices i and j into the array such that
     * the difference between arr[i] and arr[j] is at most l and the difference
     * between i and j is at most k.
     */
    public static boolean containsNearbyAlmostDuplicate(int[] arr, int k, int l) {
        if(arr == null || arr.length == 0 || k < 1){
            return false;
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        TreeSet<Integer> bst = new TreeSet<Integer>();
        for(int i = 0; i < arr.length; i++){
            int num = arr[i];
            if(bst.floor(num) != null){
                int pred = bst.floor(num);
                if(Math.abs(pred - num) <= l){
                    return true;
                }
            }
            if(bst.ceiling(num) != null){
                int succ = bst.ceiling(num);
                if(Math.abs(succ - num) <= l){
                    return true;
                }
            }
            queue.add(num);
            bst.add(num);
            if(bst.size() > k){
                bst.remove(queue.poll());
            }
        }
        return false;
    }
    
    public static void main(String[] args){
        int[] num = {1, 10, 20, 30, -7, 100};
        System.out.println(containsNearbyAlmostDuplicate(num, 4, 8)); //k, l
    }
}