优步面经

Email domain address typo, need to figure out and return correct domain name. e.g. yhaoo–> yahoo, giaml –> gmail, hmailot–> hotmail.
Solution: HashMap, key as sorted string, value as correct email domain.

其实是anagram

public String getEmail(String s) {
  Map<String, String> map = new HashMap<String, String>();
  //init the map with the string
  
  String[] email = {"yahoo", "gmail", "hotmail" ..};
  for (String e : email) {
    map.put(sortByChar(e), e);
  }
  if (map.containsKey(sortByChar(s)) {
    return map.get(sortByChar(s));
  }
  return null;
}

private String sortByChar(String s) {
  char[] charArray = s.toCharArray();
  Arrays.sort(charArray);
  return new String(charArray);
}

Elevator Design

Design Uber, web service, API, database.

given a > b, b > c, if pass in c > a return false, if a > c return true

感觉像是topological sort,实际上直接dfs就可以,因为只要找到了back edge,就说明顺序是不对的

如果对于cross edge,假设我们认为cross edge return false的话,就好办了,我们只需要按顺序搜,搜到了的话就return true,不然就return false。如果相反的话,我们就要把input反过来,如果搜到了就return false,不然就return true。这里假设input保证没有loop。

public boolean checkOrder(char c1, char c2, List<Char[]> orders) {
  Map<Character, Set<Character>> adjMatrix = new HashMap<Character, Set<Character>>();
  for (Char[] pair : orders) {
    char from = pair[0];
    char to = pair[1];
    Set<Character> set = null;
    if (!adjMatrix.containsKey(from)) {
      set = new HashSet<Character>();
      adjMatrix.put(from , set);
    } else {
      set = adjMatrix.get(from);
    }
    set.add(to);
  }
  Set<Character> visited = new HashSet<Character> visited;
  return dfsFind(adjMatrix, c1, c2);
}

private boolean dfsFind(adjMatrix, char start, char target) {
  if (start == target) {
    return true;
  }
  Set<Character> curr = adjMatrix.get(start);
  for (Character c : curr) {
    if (dfsFind(adjMatrix, c, target)) {
      return true;
    }
  }
  return false;
}

做tiny url
其实就是转换成base 62的数。

public String getUrl(int id) {
  if (id == 0) {
    return null;
  }
  List<Character> list = new ArrayList<Character>();
  for (char c = '0'; c <= '9'; c++) {
    list.add(c);
  }
  for (char c = 'a'; c <= 'z'; c++) {
    list.add(c);
  }
  for (char c = 'A'; c <= 'Z'; c++) {
    list.add(c);
  }
  StringBuilder sb = new StringBuilder();
  while (id != 0) {
    int idx = id%62;
    sb.insert(0, list.get(idx));
    id /= 62;
  }
  return sb.toString();
}

Spiral Array Print

public void printSpirialMatrix(int [][] matrix) {
  if (matrix == null || matrix.length == 0) {
    return
  }
  int sR = 0;
  int eR = matrix.length-1;
  int sC = 0;
  int eC = matrix[0].length-1;
  while(sR <= eR && sC <= eC) {
    //first row
    for (int i=sC; i<eC; i++) {
      print(matrix[sR][i]);
    }
    //right col
    for (int i=sR; i<eR; i++) {
      print(matrix[i][eC]);
    }
    //bottom row
    if (sR < eR) {
      for(int i=eC; i>sC; i--) {
        print(matrix[eR][i];
      }
    }
    //left col
    if (sC < eC) {
      for (int i=eR; i>sR; i--) {
        print(matrix[i][sC]);
       }
    }
    sR++;
    eR--;
    sC++;
    eC--;
  }
}

电面:
String Break
将一个String分成若干个substring,每个substring有大小限制k,且在末尾有固定格式代表这是第几个substring

Example: “this is a string” -> “this is (1/2)” “a string (2/2)”

这道题就是数学题了

如果总的长度是n,假设每个string 分别是k个那么大,但是由于需要在后面append长度信息。所以不可以直接除以k, 而要加上append的信息,那么我们假设append的信息的长度是l, 那么最多可以将整个string 分成power(10, l) 份。

l*2 + 3 + n/(10^l) <= k

int n = s.length();
int l = 1;
while(l*2 + 3 + n/(10^l) > k) {
  l++;
}
List<String> res = new ArrayList<String>();
//now we have l (the space to store extra)
int parts = Math.ceiling(n/(float)(k-l)); //make sure to use float otherwise int division will be used
int start = 0;
int count = 1;
StringBuilder sb = new StringBuilder();
for (int i=0; i<s.length() && start<s.length(); i++) {
  if (s.charAt(i) == ' ') {
    String tmp = s.substring(start, i);
    if (sb.length() + tmp.length() + 1 > k - 2*l - 3) {
      sb.append(String.valueOf(count));
      sb.append('/');
      sb.append(String.valueOf(parts));
      count++;
      res.add(sb.toString());
      sb = new StringBuilder();
    }
    sb.append(tmp);
    sb.append(" ");
    start = i+1;
  }
}
//what was left in sb;
if (sb.length() != 0) {
  sb.append(String.valueOf(count));
  sb.append('/');
  sb.append(String.valueOf(parts));
  res.add(sb.toString());
}
return res;
}

题目就是flatten json to a list of map, 有一段json,比如说如下:
{
“uuid”: “abc”,
“properties”: {
“sessionName”: “Test session name”
“waypoints”: [
{“uuid”: “def”, “properties”: {“latitude”: 3}}
]
}
}
把它转化成List<Map>, map里面uuid是key, properties是value。 所以结果应该像下面

[

{“uuid”: “abc”, “properties”: {“sessionName”: “Test session name”, “waypoints”: [“def”]}},

{“uuid”: “def”, “properties”: {“latitude”: 3}},

]
其实就是recursion求,每次把一个object放进map以后,要用一个recursive的function 处理一下每个attribute。如果是array的话要recursive的把array里的所有object都放进res里面,并且对每个object再进行recursion

public class Solution {
	public List<Map<String, Object>> flatternJSON(String jsonString) {
		JSONParser parser = new JSONParser();
		List<Map<String, Object>> res = new ArrayList<Map<String, Object>>();
		try {
			JSONObject jObj = (JSONObject)parser.parse(jsonString);
			Map<String, Object> map = new HashMap<String, Object>();
			String key = (String) jObj.get("uuid");
			Object value = jObj;
			map.put(key, jObj);
			recursiveProcess(jObj, res);
			return res;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	private void recursiveProcess(JSONObject jObj, List<Map<String, Object>>res) {
		Iterator iter = jObj.keySet().iterator();
		while(iter.hasNext()) {
			
			String key = (String) iter.next();
			Object obj = jObj.get(key);
			if (obj instanceof String) {
				continue;
			} else if (obj instanceof JSONArray) {
				JSONArray array = (JSONArray)obj;
				Iterator arrIter = array.iterator();
				JSONArray newArray = new JSONArray();
				while(arrIter.hasNext()) {
					JSONObject o = (JSONObject) arrIter.next();
					newArray.add(o.get("uuid"));
					Map<String, Object> map = new HashMap<String, Object>();
					map.put((String) o.get("uuid"), obj);
					res.add(map);
					recursiveProcess(o, res);
				}
				jObj.put(key, newArray);
				
			} else {
				recursiveProcess((JSONObject)obj, res);
			}
		}
	}
}
}  

1,Run-Length Encoding,就是把aaabbcccaaaa变成3a2b3c4a这样,要求encode后的信息要比原来的短。

	public String encode(String s) {
		  int start = 0;
		  StringBuilder res = new StringBuilder();
		  for (int i=1; i<=s.length(); i++) {
		    if (i == s.length() || s.charAt(i) != s.charAt(start)) {
		        if (i - start > 2) {
		          res.append(String.valueOf(i-start));
		          res.append(s.charAt(start));
		        } else {
		          res.append(s.substring(start, i));
		        }
		        start = i;
		    }
		  }
		  
		  return res.toString();
		}

首先暴力扫描之。然后问有什么问题,答曰decode的时候111aaa会encode成313a然后decode成313个a。提出每encode一个就插入一个特殊符号标记,他说可以。然后追加问是否可以不用特殊符号,答曰创建新的计数单位,比如用A代表1B代表2,然后aaa就变成Ca(you get the idea),这样就不需要插入额外符号了。

3. Coding Question,用的coderPad, 比较两个Map Object,Map的Value可能有两种情况
1. Strings; 2. Map objects

public boolean compare(Object obj1, Object obj2) {
  if (obj1 instance of String && obj2 instance of String) {
    return (String)obj1.equals((String)obj2);
  }
  
  if(obj1 instance of Map<String, Object> && obj2 instance of Map<String, Object>) {
    Map<String, Object> map1 = (Map<String, Object>) obj1;
    Map<String, Object> map2 = (Map<String, Object>) obj2;
    if (map1.size() != map2.size()) {
      return false;
    }
    Iterator iter = map1.keySet().iterator();
    while (iter.hasNext()) {
      String key = (String)iter.next();
      if (!map2.containsKey(key)) {
        return false;
      }
      if (!compare(map1.get(key), map2.get(key)) {
        return false;
      }
    }
    return true;
  }
}

Given an input string, reverse the string word by word. A word is defined as a sequence of non-space characters.

The input string does not contain leading or trailing spaces and the words are always separated by a single space.

For example,
Given s = “the sky is blue”,
return “blue is sky the”.

Could you do it in-place without allocating extra space?


public String reverse(String s) {
  //reverse the whole string
  int start = 0;
  int end = s.length()-1;
  StringBuilder sb = new StringBuilder(s);
  while (start < end) {
    swap(sb, start, end);
    start++;
    end--;
  }
  //reverse word by word separated by space
  int start = 0;
  for (int i=0; i=<sb.length(); i++) {
    if (i==s.length() || s.charAt(i) == ' ') {
      reverseBetween(sb, start, i-1);
      start = i+1;
    }
  }
  return sb.toString();
}

private void swap(StringBuilder sb, int i, int j) {
  char tmp = sb.charAt(i);
  sb.setCharAt(i, sb.charAt(j);
  sb.setCharAt(j, tmp);
}  

private void reverseBetween(StringBuilder sb, int s, int e) {
  while(s < e) {
    swap(sb, s, e);
    s++;
    e--;
  }
}

形式化来说,给N个未排序的数组,找出全局中位数。
应用场景是,有N个hosts,每隔一段时间就会报告一些参数,比如qps和平均延迟等,现有某个用于monitor的机器收集信息,并且返回特定时间段内同一参数所有数据的的中位数。
先给brute force,对所有数据排序然后找中位数。

一个stream找中位数的话,可以用两个heap,一个minHeap保存大一半的数,另外一个maxHeap保存小的一半的中位数。如果新来一个数的话,我们看他是比minHeap和maxHeap最大的数比较,然后加进其中一个heap,如果在两个之间的话,假设我们就放进minHeap里,然后需要平衡一下两个heap,保证minHeap和maxHeap的size是相同的。

class MedianFinder {
  PriorityQueue<Integer> minHeap;
  PriorityQueue<Integer> maxHeap;
  public MedianFinder() {
    this.minHeap = new PriorityQueue();
    this.maxHeap = new PriorityQueue(10, Collections.reverseOrder());
  }

  public void addData(int i) {
    if (i >= minHeap.getFirst()) {
      minHeap.add(i);
    } else (
      maxHeap.add(i);
    }
    //rebalance two heaps
    if (minHeap.size() - maxHeap.size() == 2) {
      int tmp = minHeap.removeFirst();
      maxHeap.add(tmp);
    } else if (maxHeap.size() - minHeap.size() == 2) {
      int tmp = maxHeap.removeFirst();
      minHeap.add(tmp);
    }
  }

  public int getMedian() {
    if (minHeap.size() == maxHeap.size()) {
      return (minHeap.getFirst() + maxHeap.getFirst())/2
    }
    return minHeap.size() > maxHeap.size() ? minHeap.getFirst() : maxHeap.getFirst();
  }
}

search element in a roated sorted array. leetcode
Word Ladder II

这道题的idea是先用bfs找到最短路径,然后dfs找出所有的结果。

第一轮: Happy number
第二轮: 罗马数字 -> 阿拉伯数字

Happy number就是按照happy number的算法一直算,但是要注意已经visited过了的要记下来,

罗马数字转换成阿拉伯数字的话,就是要一个Map,然后注意每次greedy pick最大的那个数append到结果的右边即可

1. 设计excel, 先实现基本功能再优化(比如存图片怎么弄)
2. 给一个tuple list, 按weight random select. 比如给 [(“hello”, 2.34), (“world”, 4.68)…] world出现的概率是hello的两倍.
第二题, reverse string的变种。 只reverse word不reverse punctuation。比如 “this,,,is.a word” -> “word,,,a.is this”
这道题可以考虑用两个stack,一个用来reverse word,另外一个保存punctuation。

	public String reverse(String s) {
		  Stack<String> wStack = new Stack<String>();
		  Queue<String> pQueue= new LinkedList<String>();
		  int start = 0;
		  boolean isChar = true;
		  int end = 0;
		  for (int i=0; i<s.length(); i++) {
		    char c = s.charAt(i);
		    if (!Character.isLetter(c)) {
		      if (isChar) {
		        wStack.push(s.substring(start, i));
		        start = i;
		        isChar = false;
		      } else {
		        continue;
		      }
		    } else {
		      if (isChar) {
		        continue;
		      } else {
		        pQueue.add(s.substring(start, i));
		        start = i;
		        isChar = true;
		      }
		    } 
		  }
		  //last word or punctuation
		  if (isChar) {
		    wStack.push(s.substring(start));
		  } else {
		    pQueue.add(s.substring(start));
		  }
		  //form the new string, assuming always start with a word
		  StringBuilder sb = new StringBuilder();
		   while (!wStack.isEmpty()) {
		     sb.append(wStack.pop());
		     if (!pQueue.isEmpty()) {
		    	 sb.append(pQueue.remove());
		     }
		   }
		   return sb.toString();
		}

3. bar raiser. 是一个front end engineer (我面的是backend)但要我把我的project给他讲清楚。结果不讲不知道一讲吓一跳,backend懂得比我还多
4. design一个uber eat。说是system design结果我感觉更像product design
5. engineering manager. 一个老中 刚来没多久。问了我许多问题结果感觉对我不大满意。比如问我写service到底理解到多deep。data storage平时接触没(确实没怎么 – 都在application层面 – 摊手)。

Delete and insert in a binary tree

class TreeNode {
  TreeNode left;
  TreeNode right;
  int val;
  public TreeNode(int v) {
    this.val = v;
  }
}

class Solution {
  public static void main(String[] args) {
    Solution s = new Solution();
    TreeNode root = new TreeNode(3);
    s.insert(root, 2);
    s.insert(root, 3);
    s.insert(root, 4);
    s.insert(root, 5);
    s.insert(root, 6);
 
    assert s.contains(root, 6) != null;
    s.delete(root, s.contains(root, 6));
    assert s.contains(root, 6) == null;
    System.out.println("Success");
  }
  
  public TreeNode insert(TreeNode n, int v) {
    if (n == null) {
      return new TreeNode(v);
    }
    
    if (v > n.val) {
      TreeNode t = insert(n.right, v);
      n.right = t;
    } else if (v < n.val) {
      TreeNode t = insert(n.left, v);
      n.left = t;
    }
    return n;
  }
  
  
  public TreeNode delete(TreeNode root, TreeNode n) {
    if (root.val == n.val) {
      if (root.left == null) {
        return root.right;
      }
      if (root.right == null) {
        return root.left;
      }
      TreeNode l = findLeft(root.right);
      int tmp = root.val;
      root.val = l.val;
      l.val = tmp;
      delete(root.right, l);
      return root;
    } else {
      if (n.val < root.val) {
        root.left = delete(root.left, n);
      } else {
        root.right = delete(root.right, n);
      }
      return root;
    }
  }
  
  public TreeNode contains(TreeNode root, int value) {
    if (root == null) {
      return null;
    }
    if (root.val == value) {
      return root;
    }
    if (value > root.val) {
      return contains(root.right, value);
    }
    return contains(root.left, value);
  }
 
  private TreeNode findLeft(TreeNode root) {
    if (root.left == null) {
      return root;
    }
    return findLeft(root.left);
  }
}

mirror tree

class Solution {
  public static void main(String[] args) {
    Solution s = new Solution();
    TreeNode root = new TreeNode(1);
    TreeNode l1 = new TreeNode(2);
    TreeNode r1 = new TreeNode(3);
    root.left = l1;
    root.right = r1;
    TreeNode l2 = new TreeNode(4);
    TreeNode r2 = new TreeNode(5);
    TreeNode r3 = new TreeNode(6);
    l1.left = l2;
    l1.right = r2;
    r1.right = r3;
    
    //api under test
    s.mirror(root);
    
    //assertion
    assert root.val == 1;
    assert root.left.val == 3;
    assert root.right.val == 2;
    assert root.left.left.val == 6;
    assert root.left.right == null;
    assert root.right.left.val == 5;
    assert root.right.right.val == 4;
    System.out.println("Success");
  } 
  
  public void mirror(TreeNode n) {
    if (n == null) {
      return;
    }
    
    TreeNode tmp = n.left;
    n.left = n.right;
    n.right = tmp;
    mirror(n.left);
    mirror(n.right);
  }
}

shorten url base 62

Matrix Region Sum
http://www.ardendertat.com/2011/09/20/programming-interview-questions-2-matrix-region-sum/

First preprocess so each matrix contains the sum from left most to the current index, then calculating the sum of a certain region will be the sum bottom right – bottom left – top right + top left.

http://www.ardendertat.com/2011/09/20/programming-interview-questions-2-matrix-region-sum/

subsets

class Solution {
  public static void main(String[] args) {   
    Solution s = new Solution();
    List<Integer> test = new ArrayList<Integer>();
    test.add(1);
    test.add(2);
    test.add(3);
    List<List<Integer>> res = s.subsets(test);
    for (List<Integer> l : res) {
      for(int i : l) {
        System.out.print(i);
        System.out.print(',');
      }
      System.out.print('\n');
    }
    System.out.println("Success");
  } 
  
  public List<List<Integer>> subsets(List<Integer> input) {
    List<List<Integer>> res = new ArrayList<List<Integer>>();
    if (input.size() == 0) {
      res.add(new ArrayList<Integer>());
      return res;
    }
    
    for (int i=0; i<input.size(); i++) {
      List<Integer> next = new ArrayList<Integer>(input);
      next.remove(i);
      List<List<Integer>> list = subsets(next);
      for(List<Integer> l : list) {
        l.add(0, input.get(i));
        res.add(l);
      }
    }
    return res;
  }
}

combination:

class Solution {
  public static void main(String[] args) {   
    Solution s = new Solution();
    List<Integer> test = new ArrayList<Integer>();
    test.add(1);
    test.add(2);
    test.add(3);
    List<List<Integer>> res = s.combination(test, 2);
    for (List<Integer> l : res) {
      for(int i : l) {
        System.out.print(i);
        System.out.print(',');
      }
      System.out.print('\n');
    }
    System.out.println("Success");
  } 
  
  public List<List<Integer>> combination(List<Integer> input, int k) {
    if (k > input.size()) {
      return null;
    }
    
    List<List<Integer>> res = new ArrayList<List<Integer>>();
    
    if (k == input.size()) {
      res.add(input);
      return res;
    }
    
    if (k == 0) {
      res.add(new ArrayList<Integer>());
      return res;
    }
    
    for (int i=0; i<input.size(); i++) {
      int curr = input.get(i);
      List<Integer> next = new ArrayList<Integer>();
      for (int j=i+1; j<input.size(); j++) {
        next.add(input.get(j));
      }
      List<List<Integer>> list = combination(next, k-1);
      if (list != null) {
        for (List<Integer> l : list) {
          l.add(0, curr);
          res.add(l);
        }
      } {
    }
    
    return res;
  }
}

1. regex match (假设*match to any number of character proceeding it while ? match any character) use dynamic programming.
public boolean regMatch(String s, String p) {
int [][] match = new int[p.length()+1][s.length()+1];
for (int i = 0; i<p.length(); i++) {
for (int j=0; jyes,
lockern->false.

6. HM闲聊,问项目哪里吸引我,为什么Uber。

1. 3个长度一样的array a1, a2, a3, 找出所有 A + B = C 的组合,A在a1里,B在a2,C在a3里;扩展到4个数组 a2, a2, a3, a4,找出A+B+C=D的组合。。 然后扩展到n各数组;做完了又给了一道题目,不难,忘了。。

这道题就可以从两个array开始,有两种办法,一种是将其中一个arry做成hashset,然后用另外一个array去一个一个尝试,或者将两个array都sort,然后一个从start开始,一个从end开始,分别从前往后和从后往前走,看能不能碰到target的值

public List<List> getSum(List a1, List a2, int target) {
Set set = new HashSet();
List<List> res = new ArrayList<List>();

for(int i=0; i<a1.length; i++) {
set.add(a1[i]);
}
for(int i=0; i<a2.length; i++) {
if (set.containsKey(target – a2[i])) {
List r = new ArrayList();
r.add(target – a2[i]);
r.add(a2[i]);
res.add(r);
}
}
return res;
}

public List<List> getArraySum(List a1, List a2, List a3) {
List<List> res = new ArrayList<List>();
for(int i=0; i<a3.length; i++) {
List<List> r = getSum(a3[i]);
res.addAll(r);
}
return res;
}

2. 一个系统里面,有user 在不断的login and logout, 现在给你几组user的(username, login_time, logout_time)的数据,打印出各个时间
点系统有几个active user;follow-up,修改我的实现,让我的函数支持 类似JS的callback机制.

//first sort by startTime, then by endTime. Use a heap to calculate the number of active users at the same time.

class User {
int uid;
int start;
int end;
}

class void printActiveUser(List users) {
Collection.sort(users, new Comparator(){
@Override
public int compare

3. 面我的是一个中国人神牛。因为我说我用c++,然后感觉他临时选了这道题给我。。 reader-writer problem. 用mutex 实现user-writer problem。 follow-up,问会有什么问题,其实会有starving 的情况发生,然后一起商量怎么处理.

Leave a comment