Snapchat phone interview

1.一开始问了很多暑假实习的内容,coding题目是一个矩阵里某些位置有墙,给一个出发点及目的地,求最短距离。 follwup是现在墙可以打破,没打破一个cost为1,求cost最小的路线

follow up : use min heap to record the cost as proceeding

    //test case input:
    [
        [0,0,0,s,0,0],
        [0,0,0,0,0,0],
        [0,0,0,0,0,0],
        [0,0,0,0,0,0],
        [0,0,0,0,0,e],
        [0,0,0,0,0,0],
    ]

import java.util.*;
public class FindPath {
    private int[][] dirt = new int[][]{{-1,0},{0,-1},{1,0},{0,1}};
    public static void main(String[] args) {
        int[][] matrix = new int[][]{{0,0,1,0,1,0},{0,0,0,0,1,0},{0,0,0,1,0,0},{0,0,0,1,0,0},{0,0,1,0,0,0},{0,0,0,0,0,0}};
        int[] start = new int[]{0,3};
        int[] end = new int[]{4,5};
        FindPath test = new FindPath();
        System.out.println(test.findpath1(matrix,start,end));
    }
    public int findpath1(int[][] matrix, int[] start, int[] end){
        if(matrix.length==0||matrix[0].length==0) return -1;
        int row = matrix.length;
        int col = matrix[0].length;
        Queue<int[]> qe = new LinkedList<>();
        qe.offer(new int[]{start[0],start[1],0});
        matrix[start[0]][start[1]] = 2;
        while(!qe.isEmpty()){
            int[] crt = qe.poll();
            int lvl = crt[2];
            if(crt[0]==end[0]&&crt[1]==end[1]) return lvl;
            for(int[] ea : dirt){
                int x = crt[0] + ea[0];
                int y = crt[1] + ea[1];
                if(x<0||x>=row||y<0||y>=col) continue;
                if(matrix[x][y]!=0) continue;
                qe.offer(new int[]{x,y,lvl+1});
                matrix[x][y] = 2;
            }
        }
        return -1;
    }
}
import java.util.*;
public class Test {
    public int minCost(int[][] maze, int start_x, int start_y, int end_x, int end_y){
        if(maze==null||maze.length==0||maze[0].length==0) return -1;
        int row = maze.length;
        int col = maze[0].length;
        boolean[][] visited = new boolean[row][col];
        PriorityQueue<Position> heap = new PriorityQueue<>(new Comparator<Position>(){
            public int compare(Position p1, Position p2){
                return p1.cost-p2.cost;
            }
        });
        heap.offer(new Position(start_x,start_y,0,null));
        visited[start_x][start_y] = true;
        int[][] dirts = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
        while(!heap.isEmpty()){
            Position crt = heap.poll();
            for(int[] dirt : dirts){
                int next_x = crt.x + dirt[0];
                int next_y = crt.y + dirt[1];
                if(next_x<0||next_y<0||next_x>=row||next_y>=col||visited[next_x][next_y]) continue;
                if(next_x == end_x && next_y == end_y) return crt.cost;
                int cost = crt.cost + (maze[next_x][next_y] == 1 ? 1 : 0);
                heap.offer(new Position(next_x,next_y,cost,crt));
            }
        }
        return -1;
    }
    public class Position {
        int x,y;
        Position prev;
        int cost;
        public Position(int x, int y, int cost, Position prev){
            this.x = x;
            this.y = y;
            this.cost = cost;
            this.prev = prev;
        }
    }
    public static void main(String[] args) {
        Test test = new Test();
        int[][] maze = new int[][]{{1,1,1,8,0,1},{1,1,1,1,1,1},{1,1,1,1,1,1},{1,1,1,1,0,1},{1,1,1,1,1,8},{1,1,1,1,1,1}};
        // int[][] maze = new int[][]{{8,1,1},{1,1,1},{1,1,8}};
        for(int[] row : maze) System.out.println(Arrays.toString(row));
        System.out.println(test.minCost(maze,0,3,4,5));
    }
}

2.detect cycle in directed graph

import java.util.*;
public class DetectGraphCycle {
    public class Node {
        int val;
        List<Node> next;
        public Node(int val){
            this.val = val;
            next = new ArrayList<>();
        }
    }
    public List<Node> generateGraph(){
        List<Node> graph = new ArrayList<>();
        Node g1 = new Node(1);
        graph.add(g1);
        Node g2 = new Node(2);
        graph.add(g2);
        Node g4 = new Node(4);
        graph.add(g4);
        Node g5 = new Node(5);
        graph.add(g5);
        Node g6 = new Node(6);
        graph.add(g6);
        g1.next.add(g2);
        g4.next.add(g1);
        g4.next.add(g5);
        g5.next.add(g6);
        g6.next.add(g4);
        return graph;
    }
    public boolean hasCycle(List<Node> graph){
        Set<Node> whiteset = new HashSet<>();
        Set<Node> grayset = new HashSet<>();
        Set<Node> blackset = new HashSet<>();
        for(Node ea : graph){
            whiteset.add(ea);
        }
        while(whiteset.size()>0){
            Node crt = whiteset.iterator().next();
            if(DFS(crt,whiteset,grayset,blackset)) return true;
        }
        return false;
    }
    public boolean DFS(Node crt, Set<Node> whiteset, Set<Node> grayset, Set<Node> blackset){
        whiteset.remove(crt);
        grayset.add(crt);
        for(Node ea : crt.next){
            if(blackset.contains(ea)) continue;
            if(grayset.contains(ea)) return true;
            if(DFS(ea,whiteset,grayset,blackset)) return true;
        }
        grayset.remove(crt);
        blackset.add(crt);
        return false;
    }
    public static void main(String[] args) {
        DetectGraphCycle test = new DetectGraphCycle();
        System.out.println(test.hasCycle(test.generateGraph()));
    }
}

3.Bigint实现加法。题目简单,最好代码一遍过

import java.util.*;
public class BigInt {
    public String add(String s1, String s2){
        StringBuilder rst = new StringBuilder();
        int idx1 = s1.length()-1;
        int idx2 = s2.length()-1;
        int carry = 0;
        while(idx1>=0||idx2>=0){
            int sum = carry;
            if(idx1>=0) sum += s1.charAt(idx1--)-'0';
            if(idx2>=0) sum += s2.charAt(idx2--)-'0';
            rst.append(sum%10);
            carry = sum/10;
        }
        if(carry!=0) rst.append(carry);
        return rst.reverse().toString();
    }
    public static void main(String[] args) {
        BigInt test = new BigInt();
        String s1 = "1231231";
        String s2 = "234234";
        System.out.println(test.add(s1,s2));
    }
}

大数乘法加法减法

4.给一个二维数组,对角线打印

    1 2 3 4
    5 6 7 8
    9 10 11 12

打印出

    1
    2 5
    3 6 9
    4 7 10
    8 11
    12
import java.util.*;
public class PrintArray {
    public List<List<Integer>> print(int[][] ipt) {
        List<List<Integer>> rst = new ArrayList<>();
        if(ipt.length==0||ipt[0].length==0) return rst;
        int row = ipt.length;
        int col = ipt[0].length;
        int n = row+col-2;//each line
        for(int i=0;i<=n;i++){
            rst.add(new ArrayList<>());
            for(int j=Math.max(0,i-col+1);j<=Math.min(i,row-1);j++){
                rst.get(i).add(ipt[j][i-j]);
            }
        }
        return rst;
    }
    public static void main(String[] args) {
        PrintArray test = new PrintArray();
        int[][] ipt = new int[][]{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
        System.out.println(test.print(ipt));
    }
}

5.给定字符串A,B, 判断A中是否存在子串是B的anagram

public class Anagram {
    public boolean hasAnagram(String s1, String s2){
        int[] map = new int[128];
        int cnt = s2.length();
        for(int i=0;i<s2.length();i++) map[s2.charAt(i)]++;
        int L=0,R=0;
        while(R < s1.length()){
            char c = s1.charAt(R++);
            map[c]--;
            if(map[c]>=0) cnt--;
            if(R>=s2.length()){
                if(cnt==0) return true;
                char k = s1.charAt(L++);
                map[k]++;
                if(map[k]>0) cnt++;
            }
        }
        return false;
    }
    public static void main(String[] args) {
        Anagram test = new Anagram();
        System.out.println(test.hasAnagram("fsssdweeas","sdf"));
    }
}

6.用array实现arraylist

int[] array;
int size;

7.写一个level order traversal

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> rst = new ArrayList<>();
        List<Integer> crt = new ArrayList<>();
        Queue<TreeNode> qe = new LinkedList<>();
        if(root==null) return rst;
        qe.offer(root);
        TreeNode dummy = new TreeNode(0);
        qe.offer(dummy);
        while(!qe.isEmpty()){
            TreeNode n = qe.poll();
            if(n==dummy){
                rst.add(new ArrayList<>(crt));
                crt.clear();
                if(!qe.isEmpty()) qe.offer(dummy);
                continue;
            }
            if(n.left!=null) qe.offer(n.left);
            if(n.right!=null) qe.offer(n.right);
            crt.add(n.val);
        }
        return rst;
    }
}

8.给你一个integer set和一个target,找出set用所有integer和能组成target的, 数字可以重复,排列可以不一样,比如set 是 1 3 5,target 是5, 那么需要输出 3 1 1, 1 3 1, 1 1 3, 是Leetcode上的变种,想了一下用一个dfs搞定。follow up是数字不重复怎么办,其实就是每次取一个数后将他从set中移除,回朔时在加上去。

import java.util.*;
public class CombinationSum {
    private List<List<Integer>> rst = new ArrayList<>();
    private List<Integer> crt = new ArrayList<>();
    public List<List<Integer>> combination(int[] mem, int tar){
        rst.clear();
        crt.clear();
        backtracking(mem,0,tar);
        return rst;
    }

    public List<List<Integer>> combination2(int[] mem, int tar){
        rst.clear();
        crt.clear();
        backtracking2(mem,0,0,tar);
        return rst;
    }

    public void backtracking(int[] mem, int sum, int tar){
        if(sum>tar) return;
        if(sum==tar){
            rst.add(new ArrayList<>(crt));
            return;
        }
        for(int ea : mem){
            crt.add(ea);
            backtracking(mem,sum+ea,tar);
            crt.remove(crt.size()-1);
        }
    }

    public void backtracking2(int[] mem, int idx, int sum, int tar){
        if(sum>tar) return;
        if(sum==tar){
            rst.add(new ArrayList<>(crt));
            return;
        }
        for(int i=idx;i<mem.length;i++){
            crt.add(mem[i]);
            backtracking2(mem,i+1,sum+mem[i],tar);
            crt.remove(crt.size()-1);
        }
    }

    public static void main(String[] args) {
        CombinationSum test = new CombinationSum();
        int[] mem = new int[]{1,3,5};
        System.out.println(test.combination2(mem,4));
    }
}

9.level order travesal, 要求不要用recursive, 用了bfs(See above 7 problem)

10.Implement a BigInt class,Implement the multiply method(See problem summary bigint)

11.LeetCode 原题 Binary Tree Vertical Order Traversal

import java.util.*;
public class VerticalOrderTrav {
    public List<List<Integer> verticalorder(TreeNode root){
        List<List<Integer>> rst = new ArrayList<>();
        if(root==null) return rst;
        Map<Integer,List<Intege>> map = new HashMap<>();
        Queue<TreeNode> qe = new LinkedList<>();
        Queue<Integer> lvl = new LinkedList<>();
        qe.offer(root);
        lvl.offer(0);
        int L=0,R=0;
        while(!qe.isEmpty()){
            TreeNode crt = qe.poll();
            int crt_lvl = lvl.poll();
            if(!map.containsKey(crt_lvl)) map.put(crt_lvl, new ArrayList<>());
            map.get(crt_lvl).add(crt.val);
            if(crt.left!=null){
                qe.offer(crt.left);
                lvl.offer(crt_lvl-1);
                L = Math.min(L,crt_lvl-1);
            }
            if(crt.right!=null){
                qe.offer(crt.right);
                lvl.offer(crt_lvl+1);
                R = Math.max(R,crt_lvl+1);
            }
        }
        for(int i=L;i<=R;i++) rst.add(map.get(i));
        return rst;
    }
}

12.给你一些interviews 的起始时间和终止时间,问如何安排interview用的meeting room的数量最短。就是LC meeing room II 的变形。 要输出最后如何安排,先按照起始时间排序。 然后建一个heap, 把终止时间依次加进去。 每次加一个新的回忆, 访问heap的根来看是否有可以用的meeting room,没有就在分配一个。有的话就pop 出来复用这个room,最后跑了几个test case.小哥人不错, 一直给建议说变量名要好好起。。。面了30 分钟左右就结束了。一天了还没消息。。。。。感觉已跪, 求给个onsite的机会, 二面也行。。。。

public class MeetingRoom {
    public int minMeetingRoom(Interval[] intervals){
        if(intervals==null||intervals.length==0) return 0;
        Arrays.sort(intervals, new Comparator<Interval>(){
            public int compare(Interval i1, Interval i2){
                return i1.start-i2.start;
            }
        });
        //handle end times
        PriorityQueue<Integer> endTimes = new PriorityQueue<>();
        endTimes.offer(intervals[0].end);
        for(int i=1;i<intervals.length;i++){
            /*比如第一个时间段我们放入房间1,然后第二个时间段,
            如果和房间1的结束时间不冲突,就放入房间1,否则开辟一个房间2。
            然后第三个时间段,如果和房间1或者房间2的结束时间不冲突,就放入房间1或者2,
            否则开辟一个房间3,依次类推,最后统计开辟了多少房间,所以说房间只增或不变,不会减少
            以此来记录总共开辟了多少房间*/
            if(intervals[i].start>=endTimes.peek()) endTimes.poll();
            endTimes.offer(intervals[i].end);
        }
        return endTimes.size();
    }

    public List<List<Interval>> scheduleMeetingRoom(Interval[] intervals){
        List<List<Interval>> rst = new ArrayList<>();
        if(intervals==null||intervals.length==0) return rst;
        Arrays.sort(intervals, new Comparator<Interval>(){
            public int compare(Interval i1, Interval i2){
                return i1.start-i2.start;
            }
        });
        PriorityQueue<Interval> heap = new PriorityQueue<>(new Comparator<Interval>(){
            public int compare(Interval i1, Interval i2){
                return i1.end-i2.end;
            }
        });
        Map<Interval,Integer> map = new HashMap<>();
        rst.add(new ArrayList<>());
        rst.get(0).add(intervals[0]);
        heap.offer(intervals[0]);
        map.put(intervals[0],0);
        for(int i=1;i<intervals.length;i++){
            Interval last = heap.peek();
            int room;
            if(intervals[i].start>=last.end){
                heap.poll();
                room = map.get(last);
            }else{
                rst.add(new ArrayList<>());
                room = rst.size()-1;
            }
            rst.get(room).add(intervals[i]);
            heap.offer(intervals[i]);
            map.put(intervals[i],room);
        }
        return rst;
    }
}

13.第一轮:meeting room 输入时很多对开始时间和结束时间,比如 1:00 ~ 2:00 14:00 ~ 16:00 然后问哪些时间段这个room是被占用的

//merge intervals
public class Solution {
    public List<Interval> merge(List<Interval> intervals) {
        List<Interval> rst = new ArrayList<>();
        if(intervals==null||intervals.size()==0) return rst;
        Collections.sort(intervals, new Comparator<Interval>(){
            public int compare(Interval obj1, Interval obj2){
                return obj1.start-obj2.start;
            }
        });
        int start=intervals.get(0).start;
        int end=intervals.get(0).end;
        for(Interval itv : intervals){
            if(itv.start<=end){
                start=Math.min(start,itv.start);
                end = Math.max(end,itv.end);
            }else{
                rst.add(new Interval(start,end));
                start=itv.start;
                end=itv.end;
            }
        }
        rst.add(new Interval(start,end));
        return rst;
    }
}

第二轮:big number add 就是两个很大的数相加,要考虑小数. 面试我的人都很好,一直都在看我写代码,时不时的还帮我一下,都很友好。

    public String addincludedot(String s1, String s2){
        String[] fors1 = s1.split("\\.");
        String[] fors2 = s2.split("\\.");
        int carry = 0;
        String fir = "";
        String sec = "";
        if(fors1.length==2 && fors1.length==fors2.length){
            StringBuilder tail = new StringBuilder();
            int idx = Math.max(fors1[1].length()-1,fors2[1].length()-1);
            while(idx>=0){
                int sum = carry;
                if(idx<fors1[1].length()) sum += fors1[1].charAt(idx)-'0';
                if(idx<fors2[1].length()) sum += fors2[1].charAt(idx)-'0';
                idx--;
                tail.append(sum%10);
                carry = sum/10;
            }
            sec = tail.reverse().toString();
        }else if(fors1.length!=fors2.length){
            if(fors1.length==2){
                sec = fors1[1];
            }else{
                sec = fors2[1];
            }
        }
        StringBuilder head = new StringBuilder();
        int idx1 = fors1[0].length()-1;
        int idx2 = fors2[0].length()-1;
        while(idx1>=0||idx2>=0){
            int sum = carry;
            if(idx1>=0) sum += s1.charAt(idx1--)-'0';
            if(idx2>=0) sum += s2.charAt(idx2--)-'0';
            head.append(sum%10);
            carry = sum/10;
        }
        if(carry!=0) head.append(carry);
        fir = head.reverse().toString();
        if(sec.equals("")) return fir;
        else return fir+"."+sec;
    }

14.给一串log(function, timestamp,act), 在single thread的情况下输出各个function执行的时间段

15.valid BST 两种写法

//traverse in-order, should following increasing order
public class Solution {
    private Integer lastVal = null;
    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (!isValidBST(root.left)) {
            return false;
        }
        if (lastVal!=null && lastVal >= root.val) {
            return false;
        }
        lastVal = root.val;
        if (!isValidBST(root.right)) {
            return false;
        }
        return true;
    }
}
//recursive way
public class ValidBST {
    public boolean isValidBST(TreeNode root){
        long max = Long.MAX_VALUE;
        long min = Long.MIN_VALUE;
        return isValidBST(root,max,min);
    }
    public boolean isValidBST(TreeNode root, long max, long min){
        if(root==null) return true;
        if(root.val>=max||root.val<=min) return false;
        return isValidBST(root.left,root.val,min)&&isValidBST(root.right,max,root.val);
    }
}

16.给一个List 实现iterator, 支持next(),delete(),hasNext()

public class ListIterator {
    private List<Integer> lst;
    private int crt,size;
    public ListIterator(List<Integer> ipt){
        lst = new ArrayList<>(ipt);
        crt = 0;
        size = lst.size();
    }
    public boolean hasNext(){
        return crt<size;
    }
    public int next(){
        if(!hasNext()) return Integer.MIN_VALUE;
        return lst.get(crt++);;
    }
    public void delete(){
        if(crt-1<0||crt-1>=size) return;
        lst.remove(--crt);
        size = lst.size();
    }
}

17.find min in a sorted array稍微变了下形

So in this sorted problem, we don't need to use nums[idx] to show our answer, we could directly use a variable to record the minimum number which avoid the complexity of idx problem.

//Find Minimum in Rotated Sorted Array
public class Solution {
    public int findMin(int[] nums) {
        int L=0,R=nums.length-1;
        int min = Integer.MAX_VALUE;
        while(L<=R){
            int mid = L+((R-L)>>1);
            if(nums[mid]<=nums[R]){
                R = mid - 1;
            }else{
                L = mid + 1;
            }
            min = Math.min(min,nums[mid]);
        }
        return min;
    }
}
//Find Minimum in Rotated Sorted ArrayII
public class Solution {
    public int findMin(int[] nums) {
        if(nums==null||nums.length==0) return -1;
        int L=0, R=nums.length-1;
        int min = Integer.MAX_VALUE;
        while(L<=R){
            int mid=L+((R-L)>>1);
            if(nums[L]<nums[mid]){
                min = Math.min(min,nums[L]);
                L = mid+1;
            }else if(nums[L]>nums[mid]){
                min = Math.min(min,nums[mid]);
                R = mid-1;
            }else{
                min = Math.min(min,nums[L]);
                L++;
            }

        }
        return min;
    }
}

18.search in rotated array && min stack

public class Solution {
    public int search(int[] nums, int target) {
        int L=0,R=nums.length-1;
        while(L<=R){
            int mid = L+((R-L)>>1);
            if(nums[mid]==target) return mid;
            if(nums[L]<=nums[mid]){
                if(target<nums[L]||target>nums[mid]){
                    L = mid+1;
                }else{
                    R = mid-1;
                }
                continue;
            }
            if(nums[mid]<=nums[R]){
                if(target<nums[mid]||target>nums[R]){
                    R = mid - 1;
                }else{
                    L = mid + 1;
                }
                continue;
            }
        }
        return -1;
    }
}

19.实现ArrayList。CodePair写的,还要自己写test case。。。

20.一个string, 有空格,需要reverse string中所有的word follow up: 一个char arr, 把里面的词都reverse了

//first reverse each word, then reverse whole char array
public class Solution {
    public String reverseWords(String s) {
        String aftertrim=s.trim();
        char[] words = aftertrim.toCharArray();
        int len=words.length;
        int L=0,R=-1;
        for(int i=0;i<len;i++){
            if(words[i]==' '){
                if(L!=R) reverse(words,L,R);
                L=i+1;
                R=i;
                continue;
            }
            R++;
        }
        reverse(words,L,R);
        reverse(words,0,len-1);
        return new String(words).replaceAll(" +"," ");
    }
    public void reverse(char[] words, int L, int R){
        while(L<R){
            char c = words[L];
            words[L] = words[R];
            words[R] = c;
            L++;
            R--;
        }
    }
}

21.然后问如果给snapchat加一个feature要加什么 coding: construct binary tree from inorder and preorder 要考虑输入invalid的情况

public class ConstructTree {
    public TreeNode buildTree(int[] preorder, int[] inorder){
        if(preorder==null||inorder==null) return null;
        if(preorder.length==0||inorder.length==0) return null;
        int rootval = preorder[0];
        TreeNode root = new TreeNode(rootval);
        Integer rootidx = null;
        for(int i=0;i<inorder.length;i++){
            if(inorder[i]==rootval){
                rootidx=i;
                break;
            }
        }
        if(rootidx==null) return null;
        int[] preleft = Arrays.copyOfRange(preorder,1,rootidx+1);
        int[] preright = Arrays.copyOfRange(preorder,rootidx+1,preorder.length);
        int[] inoleft = Arrays.copyOfRange(inorder,0,rootidx);
        int[] inoright= Arrays.copyOfRange(inorder,rootidx+1,inorder.length);
        root.left = buildTree(preleft,inoleft);
        root.right= buildTree(preright,inoright);
        return root;
    }
}

22.给定一个全是正整数的array, 和一个targe值。 你可以取任意数目的elements from the array,允许有重复,然后使得这些elements的和等于target 问一共多少种solutions?

需要注意的是:只要排列不一样就视为不同的solution, 如 {1,2} 和 {2,1}算两个solutions,而不是一个。

    example: 
    array = {1,2,3}, 
    target = 4 
    solutions: 
    1. {1,1,1,1} 
    2. {1,1,2} 
    3. {1,2,1} 
    4. {2,1,1} 
    5. {1,3} 
    6. {3,1} 
    7. {2,2} 
    8. Therefore, return 7. 

最开始并没有说这个array全是正数,需要你提问,并且去确认。这个时候面试官会问你如果包含非正数, 有没有algorithm能解决这个问题。这些楼主都没有问题。
很明显要用Dynamic Programming去解。楼主一看时间不多了,来不及多想,凭直觉就上了,写了个看似正确其实是错误的解法。 用了2D array。 因为楼主把红色那句给忽视掉了,楼主的解法是针对solutions里不包含duplicate的解法,这样一来其实题目变得更难。。。面试结束之 后才发现解法本身就大错特错了,而面试的时候面试官 也没发现楼主的解法本质上就不对,只是说“看起来没问题,应该是初始的值不对”。有可能是他觉得没时间了, 没有让我去debug我自己的代码。然后他就给我大致说了他自己的解法,用1D array。然后让我把他的解法code出来,楼主很快搞定, 基本一遍就bugfree了。接着问了下他的方法的时间复杂度,和我的方法的时间复杂度。然后就是我提问的环节。随便聊了几句就结束了。

Two Method: Backtracking O(n^(k)): n is array length and k is target number. Or DP O(n*k).

23.Design

    // snapchatter send-list
    // toggle(string username) 
    // getSelectedLlist() 
    // t: a getsl: a
    // t: a b c getSl: a b c
    // t: a b a c getSl: b c

Design题我给的设计,用了doublelinkedlist,确保了toggle时的时间复 杂度为O(1)

This problem is like LRU, use doublelinkedlist to store one node and hashmap to get string->node. toggle means switch, tap once then appear, tap again then disselect.

24.Three Sum

public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> rst = new ArrayList<>();
        if(nums==null||nums.length==0) return rst;
        Arrays.sort(nums);
        int len = nums.length;
        for(int i=0;i<len-2;i++){
            int L=i+1,R=len-1;
            int trg = -nums[i];
            while(L<R){
                int sum = nums[L]+nums[R];
                if(sum==trg){
                    rst.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[L],nums[R])));
                    while(++L<len&&nums[L]==nums[L-1]);
                    while(--R>=0&&nums[R]==nums[R+1]);
                }else if(sum<trg){
                    L++;
                }else{
                    R--;
                }
            }
            while(i+1<len&&nums[i]==nums[i+1]) i++;
        }
        return rst;
    }
}

25.用前序和中序数组重建二叉树,LC 原题。(See above)

26.开始做题目,是game of life。 我虽说准备过这个面经题,我还是很无耻的打开了leetcode。。。(然后还写出了一个bug。。尼玛)面试官只要求写了建新matrix的那种,然后讨论了一下space的问题,说用int表示board还是比较大的,然后我说用boolean就小了32倍,然后提了一下wiki上面的方法,如果board很大可以用一个set只记录live的点,这样更加省。然后就完了,继续聊了一下他们的公司就结束了,总体来说还是比较愉快的。希望能move forward吧。 在谈到Ad的时候问我是否了解Snapchat Geofilter的广告策略,我当时蒙了,本来做了功课好像看过他们推出了广告Geofilter,但是随口答了一个on-demond geofilter。Game of Life,其实挺幸运的,因为面经上有,但是我coding好几个bug,最后有一个bug没调出来,是行列坐标整反了,他说思路可以,我算你对了,然后follow up,真是悔恨没仔细想这个问题:首先问时间空间能不能省,我就说可以存活着的pair,然后他们怎么判断下一轮是死是活?我说check live的邻居,然后周围死的也check一下是不是活了,他又问如果board无限大怎么办,但是就后悔自己没好好想,最后也没答出来

27.一个是计算combinations. 是理论上的计算,计算有多少种组合方式。 大概类似word break,比如#Ilovenyc 有多少种分解方式,此时先不考虑字典。

Permutation and combination: $$C_n^k$$, then k could be 0 to n

28.一个是 word break 2,给个字典,如何break Ilovenyc 问了时间复杂度,worst case是什么时候,为什么solution会比brute force search好,大概说了一下怎么剪枝。 比如word:aaaaa dict= {a, aa, aaa, aaaa, aaaaa}.

//DFS Solution:  time: O(2^n), space: O(n)
public class Solution {
    private List<String> rst = new ArrayList<>();
    private StringBuilder crt = new StringBuilder();
    private boolean[] DP;
    public List<String> wordBreak(String s, Set<String> wordDict) {
        if(s==null||s.length()==0) return rst;
        DP = new boolean[s.length()+1];
        DP[s.length()]=true;
        for(int i=s.length()-1;i>=0;i--){
            for(int j=i;j<s.length();j++){
                if(DP[j+1]&&wordDict.contains(s.substring(i,j+1))){
                    DP[i]=true;
                    break;
                }
            }
        }
        backtracking(s,0,wordDict);
        return rst;
    }
    public void backtracking(String s, int index, Set<String> wordDict){
        if(index==s.length()){
            rst.add(crt.toString().trim());
            return;
        }
        for(int i=index;i<s.length();i++){
            String tmp = s.substring(index,i+1);
            if(wordDict.contains(tmp)&&DP[i+1]){
                int len = crt.length();
                crt.append(tmp+" ");
                backtracking(s,i+1,wordDict);
                crt.setLength(len);
            }
        }
    }
}
//DP solution: time: O(n^2*k), space: O(nk)
public class Solution {
    public List<String> wordBreak(String s, Set<String> wordDict) {
        // 判断是否能够分解
        if (!helper(s, wordDict)) {
            return new ArrayList<String>();
        }

        // 记录字符串s.substring(0, i)对应的解
        HashMap<Integer, List<String>> map = new HashMap<Integer, List<String>>();
        map.put(0, new ArrayList<>());
        map.get(0).add("");

        for (int i = 1; i <= s.length(); i++) {
            for (int j = 0; j < i; j++) {
                if (map.containsKey(j) && wordDict.contains(s.substring(j, i))) {
                    if (!map.containsKey(i))
                        map.put(i, new ArrayList<>());
                    for (String str : map.get(j)) {
                        map.get(i).add(str + (str.equals("") ? "" : " ") + s.substring(j, i));
                    }
                }
            }
        }

        return map.get(s.length());
    }

    private boolean helper(String s, Set<String> wordDict) {
        boolean dp[] = new boolean[s.length() + 1];
        dp[0] = true;
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 0; j < i; j++) {
                if (dp[j] && wordDict.contains(s.substring(j, i))) {
                    dp[i] = true;
                }
            }
        }
        return dp[s.length()];
    }
}

29.上来惯例问为什么来snapchat,然后就是题给一个n+1元素的数组,元素在范围内,至少有一个重复,让你找其中任意一个duplicate 我马上说了hashset和元素变负的两种方法,他没让coding, followup如果数组只读,而且只用constant space的方法。暴力法可以, 然后followup 继续提高时间效率,二分法缩小range 这时候才给code。 以后一个问题的每一个解法都得看看,中间二分那里卡了一会儿,结果导致时间还就不少白人小哥就不再问了,想来也是被放弃了。。。 word ladder 2

//Find the Duplicate Number
public class Solution {
    public int findDuplicate(int[] nums) {
        int slow=0,fast=0;
        while(true){
            slow=nums[slow];
            fast=nums[nums[fast]];
            if(slow==fast) break;
        }
        slow=0;
        while(slow!=fast){
            slow=nums[slow];
            fast=nums[fast];
        }
        return slow;

    }
}

30.第一题是valid palindrome。判断是不是合法的palindrome。第二题说给一个string,可以add/delete/change,还可以combine几种来使他变为合法的palindrome。比如:ebabc可以先删了中间的a再把c改成e。问最少需要几步。

public class Solution {
    public boolean isPalindrome(String s) {
        if(s.equals("")) return true;
        int head=0,tail=s.length()-1;
        while(head<=tail){
            char h_s=s.charAt(head);
            char t_s=s.charAt(tail);
            if(!Character.isLetterOrDigit(h_s)){
                head++;
            }else if(!Character.isLetterOrDigit(t_s)){
                tail--;
            }else{
                if(Character.toLowerCase(h_s)==Character.toLowerCase(t_s)){
                    head++;
                    tail--;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
}
//edit distance
/*对于矩阵中的i,j位置,他可以有如下三种方式变换: 
1、从i-1,j 为T1增加一个字符,获得i,j,这样编辑距离本身就需要+1 
2、同理,从i,j-1过来,编辑距离必须+1。 
3、从i-1,j-1位置变换过来,那么这个时后,如果T1在i的取值和T2在j的取值一样,那么这个变换,编辑距离不变,如果不一样,那么就需要做替换操作,那么必须+1.
*/
public class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        int[][] DP = new int[len1+1][len2+1];
        for(int i=0;i<=len1;i++) DP[i][0] = i;
        for(int i=0;i<=len2;i++) DP[0][i] = i;
        for(int i=0;i<len1;i++){
            for(int j=0;j<len2;j++){
                DP[i+1][j+1] = Math.min(DP[i][j+1],DP[i+1][j])+1;
                DP[i+1][j+1] = Math.min(DP[i+1][j+1], DP[i][j] + (word1.charAt(i)==word2.charAt(j) ? 0 : 1));
            }
        }
        return DP[len1][len2];
    }
}

31.题目是设计一个类来存放一个无向图的边和点,我大概用的hashset来存一个点的邻居这样,follow up是问图有多满的情况下用bitmap更加合适。要写main函数和简单testcase跑一下。我是一开始有点编译错误但是编译通过之后结果是对的。感觉只要是能跑通应该就没什么问题。面试小哥是camera组的。

public class Node{
    int val;
    List<Node> next;
    public Node(int val){
        this.val = val;
        next = new ArrayList<>();
    }
}

How to use Bitmap: reference

//bitmap for longest consecutive sequence problem, array nums have to be non-negative
public class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums.length==0) return 0;
        BitSet map = new BitSet();
        for(int num : nums) map.set(num);
        int max=0,cnt=0;
        for(int i=0;i<map.size();i++){
            if(map.get(i)){
                cnt++;
            }else{
                if(cnt>max) max = cnt;
                cnt=0;
            }
        }
        return max;
    }
}

32.word abbreviation (See Snapchat OA)

34.给一个int的matrix,里面只有0和1,matrix表示i和j是朋友,如果是0表示两人不是朋友,是朋友的分成一个组,问能分几组。比如1和2是朋友,3和他们都不是朋友,那么就是2组,return 2就可以。自己写test自己测

int cnt = n;
for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
        Union And Find;
        if(matrix[i][j]==1){
            //only when they are not in a group, then union and cnt --;
            if(getroot(i)!=getroot(j)) cnt--;
        }
    }
}

35.第一题 :给一个数组,返回左边之和等于右边之和的那个index, 没有就返回-1,比如{1,2,3,2,1}, 返回2,写了好多testcase,各种情况。。。。10分钟完事 ]

public class EqualSum {
    public int equalIdx(int[] nums){
        if(nums.length==0) return -1;
        int total = 0;
        for(int num : nums ) total += num;
        int crt = 0;
        for(int i=0;i<nums.length;i++){
            int subtotal = total-nums[i];
            if(crt*2 == subtotal) return i;
            crt += nums[i];
        }
        return -1;
    }
    public static void main(String[] args) {
        EqualSum test = new     EqualSum();
        int[] nums = new int[]{3,2,2,5,2,1,4};
        System.out.println(test.equalIdx(nums));
    }
}

第二题 :给了一个Person class, 有score和nextSnap两个属性,每个Person有一个朋友的list,也就是nextSnap,输入是(Person, maxStep), 在maxStep步数以内算max score,注意的是下一个Friend可能会指向上一个Person,要注意回溯的问题。。。10分钟写好了, 输出一直不对。。从recursive改到一个乱七八糟的方法,还是不对,然后一行一行的肉眼debug,感觉没问题啊,最后发现她给的构造器有问题,score没赋值。。。。。。我去。。。。。过分了啊。。。。最后也没有follow up,直接问有什么问题么,我问你们现在做什么,下一步有什么计划。。韩国MM说是private company,不能告诉你。。。好吧,I am good, take care。。。。面经都看了,准备的也挺充分,总是一些各种各样的原因,继续努力吧。。。大家还有5月份毕业,没拿到offer的么。。

Using BFS, and Dummy Node, when meeting a dummy node then count++ and insert a new dummy node, when count equals maxstep then stop. And also use hashset to record the person that has already calculated.

36.面经题 basic calculator +-*/和数字 都是一位 没有空格 输入都是valid 所以不用考虑corner case

follow up是 数字变成多位

然后再followup加上空格

follow up: 负数

public class Solution {
    public int calculate(String s) {
        Stack<Integer> stk = new Stack<>();
        char sign = '+';
        int num = 0;
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(c>='0'&&c<='9') num = num*10 + c -'0';
            if((c>'9'&&c<'0'&&c!=' ')||i==s.length()-1){
                if(sign=='+') stk.push(num);
                if(sign=='-') stk.push(-num);
                if(sign=='*') stk.push(stk.pop()*num);
                if(sign=='/') stk.push(stk.pop()/num);
                sign = c;
                num=0;
            }
        }
        num=0;
        while(!stk.empty()) num += stk.pop();
        return num;
    }
}

37.面试时间是上午11点,面试官是个亲切的白人小哥。上来自我介绍一下,然后聊了聊家常,得知小哥原来也是在湾区工作。之后小哥问为什么想来Snapchat,楼主说我可是你们的用户,特别喜欢里面的Stories里面的Discover类别。然后小哥问楼主最喜欢哪一个频道,楼主说Tastemade,小哥说我也喜欢啊,特别喜欢几个妹子做饭。之后就开始聊楼主的工作,问了目前干什么,工作中遇到过什么挑战。楼主说自己是做网站的,前端后端都搞。小哥问楼主喜欢什么技术,楼主说AngularJS,这时候小哥又共鸣了,貌似他也是搞网页了,然后又聊了一下。

这些有的没的说完了,然后就是做题。这里还一个小插曲,小哥问我语言是不是用JS,楼主说并不我要用Java。小哥有点愣住了,说Java我不是很熟,估计看到我web的背景所以给我安排了一个用JS的面试官。 问题一个走迷宫问题。给了一个矩阵,"1"代表起点,位于左上角;"9"代表重点,位于右下角;"0"代表通路,"5"代表墙。. 矩阵长得是这样

    [
      [1, 5, 5, 5, 5, 0],
      [0, 5, 0, 5, 5, 0], 
      [0, 5, 0, 0, 0, 0],
      [0, 5, 0, 0, 5, 0],
      [0, 0, 0, 5, 0, 9]
    ]

设计一个算法,看看这个迷宫能不能从起点走到重点。

楼主因为面试经验少,上来突然慌神了,完全不知道从哪里下手,感觉这是一个DP的问但是又不像。楼主突然跟面试官说这个问题用DFS解决,然后小哥说好,那就写代码吧。Snapchat允许查各种资料,Google Hangout也不需要Share Screen,如果运气好貌似查到原题就可以一步登天了,不过楼主并没有去查原题。自己在草稿纸画了画走迷宫的方法,然后确定这个就是DFS问题,而且准备使用递归来实现。之后楼主开始写代码,刚开始跟小哥聊一下思路,小哥没有说话,就说我这边都看得,你自己写就好了,估计小哥是跟楼主一样安静工作的人。代码写完了就是运行,这个时候问题就来了。楼主一直做web而且用leetcode刷题不用自己搭环境,对于Java的运行不是很清楚了,包括各种头文件的引用。由于小哥也不懂Java,楼主只能自己来找错。楼主急中生智打开Eclipse查以前写的代码,发现自己"static"和"length"拼错了,实在是不应该。改了这些拼写错误以后,代码就可以运行了而且结果也正确。然后小哥说能不能打印出来路径,楼主便加入了打印的代码并且输出路径数组。小哥又把迷宫改了改,运行几次说没问题了。.

import java.util.*;
public class Maze {
    private int row,col;
    public boolean hasPath(int[][] maze){
        if(maze.length==0||maze[0].length==0) return false;
        row = maze.length;
        col = maze[0].length;
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(maze[i][j]==1){
                    maze[i][j]=0;
                    return DFS(maze,i,j);
                }
            }
        }
        return false;
    }
    private boolean DFS(int[][] maze, int r, int c){
        if(r>=row||c>=col||r<0||c<0) return false;
        if(maze[r][c]==9) return true;
        if(maze[r][c]!=0) return false;
        maze[r][c] = 3;
        boolean rst = DFS(maze,r-1,c)||DFS(maze,r+1,c)||DFS(maze,r,c-1)||DFS(maze,r,c+1);
        maze[r][c] = 0;
        return rst;
    }
    public static void main(String[] args) {
        int[][] maze = new int[][]{{1,5,5,5,5,0},{0,5,0,5,5,0},{0,5,0,0,0,0},{0,5,0,0,5,0},{0,0,0,5,0,9}};
        Maze test = new Maze();
        System.out.println(Arrays.deepToString(maze));
        System.out.println(test.hasPath(maze));
    }
}

本以为还有一道题,结果小哥说就这样问我还有没有什么问题。楼主问了一下选组和Training的问题,小哥简单介绍了一下。然后楼主说没问题了,小哥说你真的没问题了么,意思再跟我聊聊啊。幸好楼主之前问过一个朋友是Snapchat的资深用户,她说新消息来的时候不知道是照片还是视频,有时候上班的时候想看结果发现是视频,搞得非常尴尬。楼主把这个问题跟小哥说了,小哥说消息之前会有红框或者紫框,一个说明是照片另一个说明是视频,楼主说我不知道啊,小哥说没事这个设计也并不是很清楚,会作为用户反馈的。之后就是小哥说楼主表现还可以,HR会在一周内给消息,简单告别就挂了。面试的第二天下午楼主就收到了HR的邮件约onsite了。

总结一下,Snapchat面试我的问题并不难,楼主感觉自己发挥一般,能给onsite真的是运气不错。感觉面试的心态真的是太重要了,还是要多面才能更加从容。遇到问题以后千万不能慌,如果想不出来算法可以现在纸上画一画,看看自己如何手工实现解法,然后把自己变成机器来思考,这样就把这个解法转换成算了。千万不要把面试当做是一件特别严肃的事情,做题并不是考试,把解题当做一个解决问题的过程就可以了。

37.第一道题是print 2d array diagonally top-down, e.g.. From 1point 3acres bbs [[1,2,3,4], [5,6,7,8], [9,10,11,12]] => 1, 2 5, 3 6 9, 4 7 10, 8 11, 12. 题外话:这道题其实隐隐约约面经里我记得有人写过zigzag打印应该就是这个。。楼主地里电面面经看得到的都自己写了,准备了了洋洋洒洒近两千行的面经代码,唯独那道当时觉得年代久而且觉得现场也能秒就没写。。就那一道。。。然后当时心情就坏了。。开始扣着写吧 一开始竟然还开了一个大小相同的数组存访问过没有,空间复杂度O(n)的。。。果断写完等着被优化,冥想半天从上边和右边开始向左下输出就好了,no space。(See above diagonally print problem)

第二道,先问知不知道anagram,两个string怎么判断是不是anagram,楼主迅速说了开128或者256空间那个,以为要问原题了。。。结果 并不是。。 问题是给一个source string和pattern string,求有没有任意一个source string的substring和pattern string互为anagram,返回true or false。让用O(n)。。当时觉得有点蒙,我擦怎么O(n)啊。。光比较就要n的复杂度了何况还要slice window。。反正是后来苦思冥想半天总算是想到了。。楼主解法是用另外一个diff map存不对应关系,key是frequency不同的characters,value是对应的difference,source多value正,pattern为负,然后slice window,没slice一位,更新diff表,每有一个value变空了从map中删除那个entry,diff map为空则说明找到了一个匹配的window返回true。。。此法时间复杂即O(n)。。空间O(n)

(See problem 5)

38.你觉得snapchat 怎么样,你有用么? 你喜欢什么功能 doge脸,说阅后即焚好酷啊,我和朋友之间发污污的东西,都用的它(其实前天才专上软件...),各种stories功能好欢乐啊,还教做饭,喜欢的不行. 说说你的经历吧,我没你的简历在手上(怎么写在面试都这样, 周一面Google也是),然后就扯了我的经历,小哥表示你做的东西好有趣啊...

开始编程,题目不难,不过刷了地里大半的电面面经以为会有重复的碰到,结果是新的,还是有点紧张,大致意思就是输入一串的double表示的sort好的timestamps, 然后一个double的windowSize, 请你找出一个起始时间区域,使得以这个范围的起始时间开始的[x, x + windowSize] 内有最多的timestamp;

  • 我先给了queue的思路,然后每次碰到新的timestamp, remove所有之前的点,remove的时候更新pre, 然后check现在queue的size, 返回最大sizes时对应的(pre, queue.head]就是answer.
  • 码完之后说,你有没有更好的思路,不要用O (n)的extra space, 我说用two pointers, 然后又吭呲吭呲地写,小哥说你其中有个地方又问题,我看了半天没发现,提示说,你有没有觉得windowSize 可能是负数。。。负数。。。
  • 你写几个unit test吧,我对java Unit test 不熟,然后愣了几愣,说我平常常做的就是给不同的输入,看输出的结果,小哥无奈。。 [求助大家,unit test 一般要怎么写啊,google了下,感觉好复杂]
import java.util.*;
public class MaxTimeStamps {
    public double[] getRange(double[] timestamps, double window){
        double[] rst = new double[2];
        if(timestamps.length==0) return rst;
        int max = 0;
        int L = 0, R = 0;
        while(R <= timestamps.length){
            if(R==timestamps.length||timestamps[L]+window<timestamps[R]){
                if(R-L>max){
                    max = R-L;
                    rst[0] = timestamps[L];
                    rst[1] = timestamps[L]+window;
                }
                L++;
                if(R==timestamps.length) break;
            }else{
                R++;
            }
        }
        return rst;
    }
    public static void main(String[] args) {
        double[] ipt = new double[]{2,4,5,7,8,9,12,13,15,16};
        double win = 4;
        MaxTimeStamps test = new MaxTimeStamps();
        System.out.println(Arrays.toString(test.getRange(ipt,win)));
    }
}

39.就是给了一个Person类,让实现打出这个Person的关系网中的所有朋友,Person有属性id, name和friendList, sample输出是这样子的:

     /* * Mike(1) {Mitch, Ryan} 
     * Mitch(2) {Mike} 
     * Ryan(3) {Mike, Lila} 
     * Lila(4) {Ryan} 
     * Mike.printFriendsGraph() : Mitch, Ryan, Lila */ 

41.given a number n, how many ways you can create a BST, for eg for n=2, o/p = 2,n = 3 , o/p is 5.

public class Solution {
    public int numTrees(int n) {
        int[] DP = new int[n+1];
        DP[0] = 1;
        for(int i=1;i<=n;i++){
            int sum = 0;
            for(int j=0;j<=i-1;j++){
                sum += DP[j]*DP[i-j-1];
            }
            DP[i] = sum;
        }
        return DP[n];
    }
}

42.Implement LRU.

43.Determine whether a graph is bipartite
Problem Explanation

import java.util.*;
public class Bipartite {
    public boolean isBipartite(int[][] graph, int src, int cnt){
        int[] colorArr = new int[cnt];
        Arrays.fill(colorArr,-1);
        colorArr[src] = -1;
        Queue<Integer> qe = new LinkedList<>();
        qe.offer(src);
        while(!qe.isEmpty()){
            int crt = qe.poll();
            for(int i=0;i<cnt;i++){
                if(graph[crt][i]==1 && colorArr[i]==-1){
                    colorArr[i] = 1-colorArr[crt];
                    qe.offer(i);
                }else if(graph[crt][i]==1 && colorArr[i] == colorArr[crt]){
                    return false;
                }
            }
        }
        return true;
    }
}

44.刚面完 是国人大哥 题目 一个板子 一个起点 一个终点 移动按照中国象棋的马 要求输出一条最短移动路径

BFS, there is 8 ways for a node.

45.第一提,给你你个数组,要你返回数组的最小值的平方是否小于最大值。题目很简单,需要注意的就是最小值的平方可能越界。 佛罗阿噗:如果这个数组不满足第一题中的条件,然后允许你执行“删除数组的第一个元素”的操作,让你返回要执行多少次,也就是删除多少个数组前面的元素后才能满足第一题中的条件。如果删完都不满足,返回-1;这一题小哥反复提示才想出来一个O(n)的做法,然后今天看还有个小bug,哎。。 接着佛罗阿噗:如果可以每次都可以选择删除第一个或者最后一个,问最少要删掉几次。。

results matching ""

    No results matching ""