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

723Candy 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

909Snakes 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+1x+2x+3x+4x+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

261Graph 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

692Top 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;
    }
}

347Top 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

635Design 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

659Split 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

853. Car Fleet

853Car Fleet
N cars are going to the same destination along a one lane road.  The destination is target miles away.
Each car i has a constant speed speed[i] (in miles per hour), and initial position position[i] miles towards the target along the road.
A car can never pass another car ahead of it, but it can catch up to it, and drive bumper to bumper at the same speed.
The distance between these two cars is ignored - they are assumed to have the same position.
car fleet is some non-empty set of cars driving at the same position and same speed.  Note that a single car is also a car fleet.
If a car catches up to a car fleet right at the destination point, it will still be considered as one car fleet.

How many car fleets will arrive at the destination?

Example 1:
Input: target = 12, position = [10,8,0,5,3], speed = [2,4,1,1,3]
Output: 3
Explanation:
The cars starting at 10 and 8 become a fleet, meeting each other at 12.
The car starting at 0 doesn't catch up to any other car, so it is a fleet by itself.
The cars starting at 5 and 3 become a fleet, meeting each other at 6.
Note that no other cars meet these fleets before the destination, so the answer is 3.

Note:
  1. 0 <= N <= 10 ^ 4
  2. 0 < target <= 10 ^ 6
  3. 0 < speed[i] <= 10 ^ 6
  4. 0 <= position[i] < target
  5. All initial positions are different.
---------------------------
也可以自己写个数据结构然后排序

按距离排序,计算每一辆车到达终点的时间,如果后后一辆车的时间少于前一辆,说明能追上。
class Solution {
    public int carFleet(int target, int[] position, int[] speed) {
        TreeMap<Integer, Double> posToTime = new TreeMap<>(Collections.reverseOrder());
        
        for (int i = 0; i < position.length; i++) {
            posToTime.put(position[i], (target - position[i]) * 1.0 / speed[i]);
        }
        
        int fleet = 0;
        double pre = 0;
        for (double time : posToTime.values()) {
            if (time > pre) {
                fleet++;
                pre = time;
            }
        }
        
        return fleet;
    }
}

497. Random Point in Non-overlapping Rectangles

497Random Point in Non-overlapping Rectangles
Given a list of non-overlapping axis-aligned rectangles rects, write a function pick which randomly and uniformily picks an integer point in the space covered by the rectangles.
Note:
  1. An integer point is a point that has integer coordinates. 
  2. A point on the perimeter of a rectangle is included in the space covered by the rectangles. 
  3. ith rectangle = rects[i] = [x1,y1,x2,y2], where [x1, y1] are the integer coordinates of the bottom-left corner, and [x2, y2] are the integer coordinates of the top-right corner.
  4. length and width of each rectangle does not exceed 2000.
  5. 1 <= rects.length <= 100
  6. pick return a point as an array of integer coordinates [p_x, p_y]
  7. pick is called at most 10000 times.
Example 1:
Input: 
["Solution","pick","pick","pick"]
[[[[1,1,5,5]]],[],[],[]]
Output: 
[null,[4,1],[4,1],[3,3]]
Example 2:
Input: 
["Solution","pick","pick","pick","pick","pick"]
[[[[-2,-2,-1,-1],[1,0,3,0]]],[],[],[],[],[]]
Output: 
[null,[-1,-2],[2,0],[-2,-1],[3,0],[-2,-2]]
Explanation of Input Syntax:
The input is two lists: the subroutines called and their arguments. Solution's constructor has one argument, the array of rectangles rectspick has no arguments. Arguments are always wrapped with a list, even if there aren't any.
--------------------------
按累加和来做,面积的大小就是点的个数,累加后2分搜索找到矩形并计算坐标。
要点:
1. 2分搜索,也可以用treeset
2. 计算坐标时 order / hi, order % hi 可以替换为 order % wid, order / wid, 顺序不能变。
画一个3 x 4的2维矩阵就明白了。

class Solution {

    private List<Integer> rec;
    private int[][] rects;
    private Random rand = new Random();
    private int total;
    
    public Solution(int[][] rects) {
        
        this.rects = rects;
        rec = new ArrayList<>();
        total = 0;
        for (int[] r : rects) {
            total += (r[3] - r[1] + 1) * (r[2] - r[0] + 1);
            rec.add(total);
        }
    }
    
    public int[] pick() {
        int next = rand.nextInt(total);
        int index = findRect(next);

        int hi = rects[index][3] - rects[index][1] + 1;
        int wid = rects[index][2] - rects[index][0] + 1;
        int low = rec.get(index) - wid * hi;
        int order = next - low;
        
        int[] rt = new int[2];        
        rt[0] = rects[index][0] + order / hi;
        rt[1] = rects[index][1] + order % hi;
        
        return rt;        
    }
    
    private int findRect(int p) {
        int left = 0, right = rects.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (p < rec.get(mid) && (mid == 0 || p >= rec.get(mid - 1))) {
                return mid;
            }else if (p >= rec.get(mid)) {
                left = mid + 1;
            }else {
                right = mid;
            }
        }
        
        return left;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(rects);
 * int[] param_1 = obj.pick();
 */

Thursday, January 17, 2019

233. Number of Digit One

233Number of Digit One
Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
Example:
Input: 13
Output: 6 
Explanation: Digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
-----------------------
以百位上1的个数举例,3种情况:
55023 -> 55 * 100
55123 -> 55 * 100 + 23  + 1
55523 -> (55 + 1) * 100

class Solution {
    public int countDigitOne(int n) {
        long rt = 0;
        for (long i = 1; i <= n; i *= 10) {
            long first = n / i, second = n % i;
            long mid = first % 10;
            if (mid == 0) {
                rt += first / 10 * i;
            }else if (mid == 1) {
                rt += first / 10 * i + second + 1;
            }else {
                rt += (first / 10 + 1) * i;
            }
        }
        
        return (int)rt;
    }
}

Wednesday, January 16, 2019

479. Largest Palindrome Product

479Largest Palindrome Product
Find the largest palindrome made from the product of two n-digit numbers.
Since the result could be very large, you should return the largest palindrome mod 1337.
Example:
Input: 2
Output: 987
Explanation: 99 x 91 = 9009, 9009 % 1337 = 987
Note:
The range of n is [1,8].
-----------------------
又恶心!
Solution#1, 找出上下边界,做遍历。超时
Solution#2 在上下边界内遍历所有的palindrome,找出符合的
class Solution {
    public int largestPalindrome(int n) {
        if (n == 1) return 9;
        
        long upper = (long)Math.pow(10, n) - 1;
        long lower = (long)Math.pow(10, n - 1);
        long max = (long)upper * (long)upper;        
        long firstHalf = max / (long)Math.pow(10, n);
        
        boolean found = false;
        long pal = 0;
        while (!found) {
            pal = createPal(firstHalf);
            for (long i = upper; i >= lower; i--) {
                if (pal > i * i) break;
                if (pal % i == 0) {
                    found = true;
                    break;        
                }
            }
            firstHalf--;
        }
        
        return (int)(pal % 1337);
    }
    
    private long createPal(long firstHalf) {
        String s = firstHalf + new StringBuilder().append(firstHalf).reverse().toString();
        return Long.parseLong(s);
    }
}

724. Find Pivot Index

724Find Pivot Index
Given an array of integers nums, write a method that returns the "pivot" index of this array.
We define the pivot index as the index where the sum of the numbers to the left of the index is equal to the sum of the numbers to the right of the index.
If no such index exists, we should return -1. If there are multiple pivot indexes, you should return the left-most pivot index.
Example 1:
Input: 
nums = [1, 7, 3, 6, 5, 6]
Output: 3
Explanation: 
The sum of the numbers to the left of index 3 (nums[3] = 6) is equal to the sum of numbers to the right of index 3.
Also, 3 is the first index where this occurs.
Example 2:
Input: 
nums = [1, 2, 3]
Output: -1
Explanation: 
There is no index that satisfies the conditions in the problem statement.
Note:

  • The length of nums will be in the range [0, 10000].
  • Each element nums[i] will be an integer in the range [-1000, 1000].

  • ----------------------
    左右各存一个sum
    class Solution {
        public int pivotIndex(int[] nums) {
            int n = nums.length;
            int left = 0;
            for (int i = 0; i < n; i++) {
                left += nums[i];
            }
            
            int right = 0;
            int rt = -1;
            for (int i = n - 1; i >= 0; i--) {
                left -= nums[i];
                if (left == right) rt = i;
                right += nums[i];
            }
            
            return rt;
        }
    }
    
    
    

    Monday, January 14, 2019

    855. Exam Room

    855Exam Room
    In an exam room, there are N seats in a single row, numbered 0, 1, 2, ..., N-1.
    When a student enters the room, they must sit in the seat that maximizes the distance to the closest person.  If there are multiple such seats, they sit in the seat with the lowest number.  (Also, if no one is in the room, then the student sits at seat number 0.)
    Return a class ExamRoom(int N) that exposes two functions: ExamRoom.seat() returning an int representing what seat the student sat in, and ExamRoom.leave(int p) representing that the student in seat number p now leaves the room.  It is guaranteed that any calls to ExamRoom.leave(p) have a student sitting in seat p.

    Example 1:
    Input: ["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]]
    Output: [null,0,9,4,2,null,5]
    Explanation:
    ExamRoom(10) -> null
    seat() -> 0, no one is in the room, then the student sits at seat number 0.
    seat() -> 9, the student sits at the last seat number 9.
    seat() -> 4, the student sits at the last seat number 4.
    seat() -> 2, the student sits at the last seat number 2.
    leave(4) -> null
    seat() -> 5, the student sits at the last seat number 5.
    
    Note:
    1. 1 <= N <= 10^9
    2. ExamRoom.seat() and ExamRoom.leave() will be called at most 10^4 times across all test cases.
    3. Calls to ExamRoom.leave(p) are guaranteed to have a student currently sitting in seat number p.
    ------------------------
    Solution #1 ref: https://leetcode.com/problems/exam-room/solution/
    用TreeSet来存位置,seat O(n), leave O(logn)
    注意要处理起始点跟终止点
    class ExamRoom {
        private TreeSet<Integer> set;
        private int n;
        public ExamRoom(int N) {
            set = new TreeSet<>();
            n = N;
        }
        
        public int seat() {
            int st = 0;
            if (set.size() > 0) {
                
                int max = set.first();
                Integer pre = null;
                
                for (Integer cur : set) {
                    
                    if (pre != null) {
                        int dis = (cur - pre) / 2;
                        if (dis > max) {
                            max = dis;
                            st = pre + dis;
                        }
                    }
                    pre = cur;
                }
                
                if (n - 1 - set.last() > max) {
                    st = n - 1;
                }
            }
            
            set.add(st);
            return st;
        }
        
        public void leave(int p) {
            set.remove(p);
        }
    }
    
    /**
     * Your ExamRoom object will be instantiated and called as such:
     * ExamRoom obj = new ExamRoom(N);
     * int param_1 = obj.seat();
     * obj.leave(p);
     */
    

    Solution #2
    PriorityQueue里存的是interval,按距离
    要点:
    1. 距离的计算方式,开头和末尾
    2. interval存的是[start, mid] [mid, end], 前后2个interval会共享一个点
    class ExamRoom {
    
        private PriorityQueue<Interval> que;
        private int n;
        public ExamRoom(int N) {
            que = new PriorityQueue<>((a, b) -> {
                if (a.dis == b.dis) return a.start - b.start;
                return b.dis - a.dis;
            });
            
            n = N;
            que.add(new Interval(-1, n));
        }
        
        public int seat() {
            Interval top = que.poll();
                
            int mid = (top.start + top.end) / 2;
            if (top.start == -1) {
                que.add(new Interval(0, top.end));
                mid = 0;
            }else if (top.end == n) {
                que.add(new Interval(top.start, n - 1));
                mid = n - 1;
            }else {
                que.add(new Interval(top.start, mid));
                que.add(new Interval(mid, top.end));
            }
            return mid;
        }
        
        public void leave(int p) {
            Interval merged = new Interval(-1,n);
            Interval head = null, tail = null;
            for (Interval top : que) {            
                if (p == 0 && top.start == 0) {
                    merged.end = top.end;
                    head = top;
                }else if (p == n - 1 && top.end == n - 1) {
                    merged.start = top.start;
                    head = top;
                }else if (top.start == p) {
                    merged.end = top.end;
                    head = top;
                }else if (top.end == p) {
                    merged.start = top.start;
                    tail = top;
                }
            }
            
            que.remove(head);
            que.remove(tail);
            que.add(new Interval(merged.start, merged.end));
        }
        
        class Interval{
            public int start;
            public int end;
            public int dis;
            public Interval(int start, int end) {
                this.start = start;
                this.end = end;
                if (start == -1) {
                    dis = end;
                }else if (end == n) {
                    dis = n - start - 1;
                }else {
                    dis = (end - start) / 2;
                }
            }
        }
    }
    

    Sunday, January 13, 2019

    890. Find and Replace Pattern

    890Find and Replace Pattern
    You have a list of words and a pattern, and you want to know which words in words matches the pattern.
    A word matches the pattern if there exists a permutation of letters p so that after replacing every letter x in the pattern with p(x), we get the desired word.
    (Recall that a permutation of letters is a bijection from letters to letters: every letter maps to another letter, and no two letters map to the same letter.)
    Return a list of the words in words that match the given pattern. 
    You may return the answer in any order.

    Example 1:
    Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
    Output: ["mee","aqq"]
    Explanation: "mee" matches the pattern because there is a permutation {a -> m, b -> e, ...}. 
    "ccc" does not match the pattern because {a -> c, b -> c, ...} is not a permutation,
    since a and b map to the same letter.

    Note:
    • 1 <= words.length <= 50
    • 1 <= pattern.length = words[i].length <= 20
    ----------------------
    class Solution {
        public List findAndReplacePattern(String[] words, String pattern) {
            List rt = new ArrayList<>();
            for (String w : words) {
                if (helper(w, pattern)) {
                    rt.add(w);
                }
            }
            
            return rt;
        }
        
        private boolean helper(String word, String p) {
            Map map = new HashMap<>();
            Set used = new HashSet<>();
            
            for (int i = 0; i < p.length(); i++) {
                char pc = p.charAt(i);
                char c = word.charAt(i);
                if (map.containsKey(pc) && map.get(pc) != c) return false;
                if (!map.containsKey(pc) && used.contains(c)) return false;
                
                map.put(pc, c);
                used.add(c);
            }
            
            return true;
        }
    }