Wednesday, January 30, 2019

salesforce

https://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=453356

Is possible
public static void main(String[] ss) {

        System.out.println(isPossible(1,4,5, 14));
    }

    static boolean isPossible(int a, int b, int c, int d) {
        if (a == c && b == d) return true;
        if (a + b > c && a + b > d) return false;
        return isPossible(a + b, b, c, d) || isPossible(a, b + a, c, d);
    }
remove dup nodes
static Node removeDup(Node root) {
        Set<Integer> set = new HashSet<>();
        Node pre = null, rt = root;

        while (root != null) {
            if (set.contains(root.val)) {
                pre.next = root.next;
            }else {
                set.add(root.val);
                pre = root;
            }

            root = root.next;
        }

        return rt;
    }
https://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=455584&extra=page%3D2%26filter%3Dsortid%26sortid%3D311%26searchoption%5B3046%5D%5Bvalue%5D%3D17%26searchoption%5B3046%5D%5Btype%5D%3Dradio%26sortid%3D311%26orderby%3Ddateline

https://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=453482&extra=page%3D2%26filter%3Dsortid%26sortid%3D311%26searchoption%5B3046%5D%5Bvalue%5D%3D17%26searchoption%5B3046%5D%5Btype%5D%3Dradio%26sortid%3D311%26orderby%3Ddateline


Sunday, January 27, 2019

723. Candy Crush

723. Candy Crush
This question is about implementing a basic elimination algorithm for Candy Crush.
Given a 2D integer array board representing the grid of candy, different positive integers board[i][j] represent different types of candies. A value of board[i][j] = 0 represents that the cell at position (i, j) is empty. The given board represents the state of the game following the player's move. Now, you need to restore the board to a stable state by crushing candies according to the following rules:
  1. If three or more candies of the same type are adjacent vertically or horizontally, "crush" them all at the same time - these positions become empty.
  2. After crushing all candies simultaneously, if an empty space on the board has candies on top of itself, then these candies will drop until they hit a candy or bottom at the same time. (No new candies will drop outside the top boundary.)
  3. After the above steps, there may exist more candies that can be crushed. If so, you need to repeat the above steps.
  4. If there does not exist more candies that can be crushed (ie. the board is stable), then return the current board.
You need to perform the above rules until the board becomes stable, then return the current board.

Example:
Input:
board = 
[[110,5,112,113,114],[210,211,5,213,214],[310,311,3,313,314],[410,411,412,5,414],[5,1,512,3,3],[610,4,1,613,614],[710,1,2,713,714],[810,1,2,1,1],[1,1,2,2,2],[4,1,4,4,1014]]

Output:
[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[110,0,0,0,114],[210,0,0,0,214],[310,0,0,113,314],[410,0,0,213,414],[610,211,112,313,614],[710,311,412,613,714],[810,411,512,713,1014]]

Explanation: 


Note:
  1. The length of board will be in the range [3, 50].
  2. The length of board[i] will be in the range [3, 50].
  3. Each board[i][j] will initially start as an integer in the range [1, 2000].
-----------------
不要想太复杂(again!)
横竖只看3位,然后标记出来
O(m * n * (m + n)), 每次扫描是 m * n, 方向上每个方向最多只能塌陷m次和n次

class Solution {
    public int[][] candyCrush(int[][] board) {
        boolean found = true;
        int m = board.length, n = board[0].length;
        
        while (found) {
            found = false;
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n - 2; j++) {
                    int val = Math.abs(board[i][j]);
                    if (val != 0 && Math.abs(board[i][j + 1]) == val 
                       && Math.abs(board[i][j + 2]) == val) {
                        
                        board[i][j] = board[i][j + 1] = board[i][j + 2] = -val;
                        found = true;
                    }
                }
            }
            
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m - 2; j++) {
                    int val = Math.abs(board[j][i]);
                    if (val != 0 && Math.abs(board[j + 1][i]) == val 
                       && Math.abs(board[j + 2][i]) == val) {
                        
                        board[j][i] = board[j + 1][i] = board[j + 2][i] = -val;
                        found = true;
                    }
                }
            }
            
            for (int c = 0; c < n; ++c) {
                int wr = m - 1;
                for (int r = m-1; r >= 0; --r)
                    if (board[r][c] > 0)
                        board[wr--][c] = board[r][c];
                while (wr >= 0)
                    board[wr--][c] = 0;
            }
        }
        
        return board;
    }
    
    
}

Saturday, January 26, 2019

909. Snakes and Ladders

909. Snakes and Ladders
On an N x N board, the numbers from 1 to N*N are written boustrophedonically starting from the bottom left of the board, and alternating direction each row.  For example, for a 6 x 6 board, the numbers are written as follows:

You start on square 1 of the board (which is always in the last row and first column).  Each move, starting from square x, consists of the following:
  • You choose a destination square S with number x+1, x+2, x+3, x+4, x+5, or x+6, provided this number is <= N*N.
    • (This choice simulates the result of a standard 6-sided die roll: ie., there are always at most 6 destinations.)
  • If S has a snake or ladder, you move to the destination of that snake or ladder.  Otherwise, you move to S.
A board square on row r and column c has a "snake or ladder" if board[r][c] != -1.  The destination of that snake or ladder is board[r][c].
Note that you only take a snake or ladder at most once per move: if the destination to a snake or ladder is the start of another snake or ladder, you do not continue moving.  (For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination square is `2`, then you finish your first move at `3`, because you do not continue moving to `4`.)
Return the least number of moves required to reach square N*N.  If it is not possible, return -1.
Example 1:
Input: [
[-1,-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1,-1],
[-1,35,-1,-1,13,-1],
[-1,-1,-1,-1,-1,-1],
[-1,15,-1,-1,-1,-1]]
Output: 4
Explanation: 
At the beginning, you start at square 1 [at row 5, column 0].
You decide to move to square 2, and must take the ladder to square 15.
You then decide to move to square 17 (row 3, column 5), and must take the snake to square 13.
You then decide to move to square 14, and must take the ladder to square 35.
You then decide to move to square 36, ending the game.
It can be shown that you need at least 4 moves to reach the N*N-th square, so the answer is 4.
Note:
  1. 2 <= board.length = board[0].length <= 20
  2. board[i][j] is between 1 and N*N or is equal to -1.
  3. The board square with number 1 has no snake or ladder.
  4. The board square with number N*N has no snake or ladder.
--------------------
一开始想太复杂了。找最短路径,简单的bfs就能搞定,不用dp。其中一些点会往回走,不用担心,visitted[] 数组就可以搞定

1. 每次都直接把board上的value给读进去,这样就可以处理每次最多只能爬一次楼梯
2. 满足1的条件下,如果是楼梯的话,只能爬楼梯,不能掷骰子

class Solution {
    public int snakesAndLadders(int[][] board) {
        int n = board.length;
        Queue<Integer> que = new LinkedList<>();
        boolean[] visited = new boolean[n * n + 1];
        visited[1] = true; 
        que.add(1);    
        
        int step = 0;
        while (!que.isEmpty()) {
            int len = que.size();
            for (;len > 0; len--) {
                int cur = que.poll();
                if (cur == n * n) return step;
                
                for (int i = 1; i <= 6; i++) {
                    int next = cur + i;
                    if (next > n * n) continue;
                    int nextValue = getValue(board, next);
                    
                    if (nextValue != -1) next = nextValue;
                    if (visited[next]) continue;
                    que.add(next);
                    visited[next] = true;
                }
            }
            
            step++;
        }
        
        return -1;
    }
    
    private int getValue(int[][] board, int i) {
        int n = board.length;
        int r = (n - 1) - (i - 1) / n;
        int c = 0;
        if ((i - 1) / n % 2 == 0) {
            c = (i - 1) % n;
        }else {
            c = n - 1 - (i - 1) % n;
        }
        
        return board[r][c];
    }
}

Friday, January 25, 2019

261. Graph Valid Tree

261. Graph Valid Tree
Given n nodes labeled from 0 to n-1 and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.
Example 1:
Input: n = 5, and edges = [[0,1], [0,2], [0,3], [1,4]]
Output: true
Example 2:
Input: n = 5, and edges = [[0,1], [1,2], [2,3], [1,3], [1,4]]
Output: false
Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0,1] is the same as [1,0]and thus will not appear together in edges.
--------------------
树的条件:
1. 没环
2. 所有的node都是连接在一起
class Solution {
    public boolean validTree(int n, int[][] edges) {
        int[] nums = new int[n];
        int[] sizes = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = i;
            sizes[i] = 1;
        }
        
        for (int[] e : edges) {
            int root1 = find(nums, e[0]);
            int root2 = find(nums, e[1]);
            if (root1 == root2) return false;
            
            if (sizes[root1] > sizes[root2]) {
                nums[root2] = root1;    
            }else {
                nums[root1] = root2;    
            }
        }
        
        int root = find(nums,0);
        for (int i = 1; i < n; i++) {
            if (root != find(nums, i)) return false;
        }
        
        return true;
    }
    
    private int find(int[] nums, int i) {
        while (i != nums[i]) {
            i = nums[i];
        }
        
        return i;
    }
    
    
}

Monday, January 21, 2019

692. Top K Frequent Words, 347. Top K Frequent Elements

692. Top K Frequent Words
Given a non-empty list of words, return the k most frequent elements.
Your answer should be sorted by frequency from highest to lowest. If two words have the same frequency, then the word with the lower alphabetical order comes first.
Example 1:
Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
Output: ["i", "love"]
Explanation: "i" and "love" are the two most frequent words.
    Note that "i" comes before "love" due to a lower alphabetical order.
Example 2:
Input: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
Output: ["the", "is", "sunny", "day"]
Explanation: "the", "is", "sunny" and "day" are the four most frequent words,
    with the number of occurrence being 4, 3, 2 and 1 respectively.
Note:
  1. You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
  2. Input words contain only lowercase letters.
Follow up:
  1. Try to solve it in O(n log k) time and O(n) extra space.
---------------------------------
用PriorityQueue 来保证前k个元素,map里存所有的元素和数量
class Solution {
    class Pair{
        public String word;
        public int count;
        public Pair(String word, int count) {
            this.word = word;
            this.count = count;
        }
    }
    
    public List<String> topKFrequent(String[] words, int k) {
        Map<String, Integer> map = getMap(words);
        
        PriorityQueue<Pair> que = new PriorityQueue<>(k, (a, b) -> {
            if (a.count == b.count) {
                return b.word.compareTo(a.word);
            }
            
            return a.count - b.count;
        });
        
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            que.add(new Pair(entry.getKey(), entry.getValue()));
            if (que.size() > k) que.poll();
        }
        
        List<String> rt = new ArrayList<>();
        
        while (!que.isEmpty()) {
            rt.add(0, que.poll().word);
        }
        
        return rt;
    }
    
    private Map<String, Integer> getMap(String[] words) {
        Map<String, Integer> map = new HashMap<>();
        
        for (String word : words) {
            map.put(word, map.getOrDefault(word, 0) + 1);
        }
        
        return map;
    }
}

347. Top K Frequent Elements
Given a non-empty array of integers, return the k most frequent elements.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Example 2:
Input: nums = [1], k = 1
Output: [1]
Note:
  • You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
  • Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
----------------------
Solution #1
HashMap + PriorityQueue
O(n lg k)
class Solution {
    
    public List<Integer> topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int n : nums) {
            map.put(n, map.getOrDefault(n, 0) + 1);
        }
        
        PriorityQueue<Map.Entry<Integer, Integer>> que = new PriorityQueue<>((a, b) -> a.getValue() - b.getValue());
        
        for (Map.Entry<Integer, Integer> e : map.entrySet()) {
            que.add(e);
            if (que.size() > k) que.poll(); 
        }
        
        List<Integer> rt = new ArrayList<>();
        while (!que.isEmpty()) {
            rt.add(que.poll().getKey());
        }
        
        return rt;
    }
}

Solution #2, bucket sort
class Solution {
    
    public List topKFrequent(int[] nums, int k) {
        Map map = new HashMap<>();
        for (int n : nums) {
            map.put(n, map.getOrDefault(n, 0) + 1);
        }
        
        // freq -> ids    
        List[] buckets = new List[nums.length + 1];
        for (Map.Entry e : map.entrySet()) {
            int frq = e.getValue();
            if (buckets[frq] == null) {
                buckets[frq] = new ArrayList<>();
            }
            
            buckets[frq].add(e.getKey());
        }
        
        List rt = new ArrayList<>();
        for (int i = buckets.length - 1; i >= 0 && rt.size() < k; i--) {
            if (buckets[i] == null) continue;
            rt.addAll(buckets[i]);
        }
        
        return rt;
    }
}

635. Design Log Storage System

635. Design Log Storage System
You are given several logs that each log contains a unique id and timestamp. Timestamp is a string that has the following format: Year:Month:Day:Hour:Minute:Second, for example, 2017:01:01:23:59:59. All domains are zero-padded decimal numbers.
Design a log storage system to implement the following functions:
void Put(int id, string timestamp): Given a log's unique id and timestamp, store the log in your storage system.

int[] Retrieve(String start, String end, String granularity): Return the id of logs whose timestamps are within the range from start to end. Start and end all have the same format as timestamp. However, granularity means the time level for consideration. For example, start = "2017:01:01:23:59:59", end = "2017:01:02:23:59:59", granularity = "Day", it means that we need to find the logs within the range from Jan. 1st 2017 to Jan. 2nd 2017.
Example 1:
put(1, "2017:01:01:23:59:59");
put(2, "2017:01:01:22:59:59");
put(3, "2016:01:01:00:00:00");
retrieve("2016:01:01:01:01:01","2017:01:01:23:00:00","Year"); // return [1,2,3], because you need to return all logs within 2016 and 2017.
retrieve("2016:01:01:01:01:01","2017:01:01:23:00:00","Hour"); // return [1,2], because you need to return all logs start from 2016:01:01:01 to 2017:01:01:23, where log 3 is left outside the range.
Note:
  1. There will be at most 300 operations of Put or Retrieve.
  2. Year ranges from [2000,2017]. Hour ranges from [00,23].
  3. Output for Retrieve has no order required.
--------------------
Solution #1, log都存在list里面,每次都要遍历
O(n), n是总大小
class LogSystem {

    private List<String[]> logs;
    private Map<String, Integer> map;
    
    public LogSystem() {
        logs = new ArrayList<>();
        map = new HashMap<>();
        map.put("Year", 4);
        map.put("Month", 7);
        map.put("Day", 10);
        map.put("Hour", 13);
        map.put("Minute", 16);
        map.put("Second", 19);
    }
    
    public void put(int id, String timestamp) {
        String[] log = new String[]{Integer.toString(id), timestamp};
        logs.add(log);
    }
    
    public List<Integer> retrieve(String s, String e, String gra) {
        int len = map.get(gra);
        List<Integer> rt = new ArrayList<>();
        for (String[] log : logs) {
            if (log[1].substring(0,len).compareTo(s.substring(0,len)) >= 0
               && log[1].substring(0,len).compareTo(e.substring(0,len)) <= 0) {
                rt.add(Integer.parseInt(log[0]));
            }
        }
        
        return rt;
    }
}

/**
 * Your LogSystem object will be instantiated and called as such:
 * LogSystem obj = new LogSystem();
 * obj.put(id,timestamp);
 * List<Integer> param_2 = obj.retrieve(s,e,gra);
 */

Solution #2用treemap来存log,然后范围搜索用subMap,注意OJ会报编译错误,但Intellij不会
O(n), n是范围内的log数量
class LogSystem {

    private TreeMap<String, List<Integer>> logs;
    private Map<String, Integer> map;
    private String min;
    private String max;
    
    public LogSystem() {
        min = "2000:01:01:00:00:00";
        max = "2017:12:31:23:59:59";
        
        logs = new TreeMap<>();
        map = new HashMap<>();
        map.put("Year", 4);
        map.put("Month", 7);
        map.put("Day", 10);
        map.put("Hour", 13);
        map.put("Minute", 16);
        map.put("Second", 19);
    }
    
    public void put(int id, String timestamp) {
        String[] log = new String[]{Integer.toString(id), timestamp};
        List<Integer> l = logs.getOrDefault(timestamp, new ArrayList<Integer>());
        l.add(id);
        logs.put(timestamp, l);
    }
    
    public List<Integer> retrieve(String s, String e, String gra) {
        int len = map.get(gra);
        NavigableMap<String, List<Integer>> sub = logs.subMap(s.substring(0,len) + min.substring(len),
                                                               true,
                                                               e.substring(0,len) + max.substring(len),
                                                               true);
        
        List<Integer> rt = new ArrayList<>();
        for (Map.Entry<String, List<Integer>> en : sub.entrySet()) {
            rt.addAll(en.getValue());
        }
        
        return rt;
    }
}

Solution #3, Trie, 每一层存的是year,month,day...
跟#2的复杂度是一样,但是写起来更麻烦

Sunday, January 20, 2019

659. Split Array into Consecutive Subsequences

659. Split Array into Consecutive Subsequences
You are given an integer array sorted in ascending order (may contain duplicates), you need to split them into several subsequences, where each subsequences consist of at least 3 consecutive integers. Return whether you can make such a split.
Example 1:
Input: [1,2,3,3,4,5]
Output: True
Explanation:
You can split them into two consecutive subsequences : 
1, 2, 3
3, 4, 5
Example 2:
Input: [1,2,3,3,4,4,5,5]
Output: True
Explanation:
You can split them into two consecutive subsequences : 
1, 2, 3, 4, 5
3, 4, 5
Example 3:
Input: [1,2,3,4,4,5]
Output: False
Note:
  1. The length of the input is in range of [1, 10000]
------------------------
第一次遍历计算出每一个数的个数
第二次遍历,每一个数都有2种可能
1. 插入之前某个连
2. 重新开一个连
贪心,每次都先选择1

needed用来保存现有的连的末尾

class Solution {
    public boolean isPossible(int[] nums) {
        Map<Integer, Integer> frq = new HashMap<>();
        Map<Integer, Integer> needed = new HashMap<>();
        for (int n : nums) {
            frq.put(n, frq.getOrDefault(n, 0) + 1);
        }
        
        for (int n : nums) {
            if (frq.get(n) == 0) continue;
            if (needed.getOrDefault(n,0) > 0) {
                needed.put(n, needed.get(n) - 1);
                needed.put(n + 1, needed.getOrDefault(n + 1, 0) + 1);
            }else if (frq.getOrDefault(n + 1, 0) > 0 
                      && frq.getOrDefault(n + 2, 0) > 0) {
                
                frq.put(n + 1, frq.get(n + 1) - 1);
                frq.put(n + 2, frq.get(n + 2) - 1);
                needed.put(n + 3, needed.getOrDefault(n + 3, 0) + 1);
            }else {
                return false;
            }
            
            frq.put(n, frq.get(n) - 1);
        }
        
        return true;
    }
}

ToDo 其他解法
https://leetcode.com/problems/split-array-into-consecutive-subsequences/discuss/106495/Java-O(n)-time-and-O(1)-space-solution-greedily-extending-shorter-subsequence