Tuesday, July 24, 2018

477. Total Hamming Distance

477Total Hamming Distance
The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
Now your job is to find the total Hamming distance between all pairs of the given numbers.
Example:
Input: 4, 14, 2

Output: 6

Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just
showing the four bits relevant in this case). So the answer will be:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
Note:
  1. Elements of the given array are in the range of to 10^9
  2. Length of the array will not exceed 10^4.
----------------------------
某一位上1的个数 * 该位上0的个数 = 该位上的hamming distance。遍历所有数字的32位,则得到结果
class Solution {
    public int totalHammingDistance(int[] nums) {
        int[] bits = new int[32];
        
        for (int num : nums) {
            
            int i = 0;
            while (num > 0) {
                if ((num & 0x1) == 1) {
                    bits[i]++;
                }
                num >>= 1;
                i++;
            }
        }
        
        int rt = 0;
        for (int bit : bits) {
            rt += bit * (nums.length - bit);
        }
        
        return rt;
    }
}

Monday, July 23, 2018

398. Random Pick Index

398Random Pick Index
Given an array of integers with possible duplicates, randomly output the index of a given target number. You can assume that the given target number must exist in the array.
Note:
The array size can be very large. Solution that uses too much extra space will not pass the judge.
Example:
int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);

// pick(3) should return either index 2, 3, or 4 randomly. Each index should have equal probability of returning.
solution.pick(3);

// pick(1) should return 0. Since in the array only nums[0] is equal to 1.
solution.pick(1);
------------------------
很直接的Reservoir sampling, 看总结
class Solution {

    private int[] nums;
    private Random rand;
    public Solution(int[] nums) {
        this.nums = nums;
        rand = new Random();
    }
    
    public int pick(int target) {
        int size = 0;
        int index = -1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                size++;
                if (rand.nextInt(size) == 0) {
                    index = i;
                }
            }
        }
        
        return index;
    }
}

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

Sunday, July 22, 2018

785. Is Graph Bipartite?

785Is Graph Bipartite?
Given an undirected graph, return true if and only if it is bipartite.
Recall that a graph is bipartite if we can split it's set of nodes into two independent subsets A and B such that every edge in the graph has one node in A and another node in B.
The graph is given in the following form: graph[i] is a list of indexes j for which the edge between nodes i and j exists.  Each node is an integer between 0 and graph.length - 1.  There are no self edges or parallel edges: graph[i] does not contain i, and it doesn't contain any element twice.
Example 1:
Input: [[1,3], [0,2], [1,3], [0,2]]
Output: true
Explanation: 
The graph looks like this:
0----1
|    |
|    |
3----2
We can divide the vertices into two groups: {0, 2} and {1, 3}.
Example 2:
Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
Output: false
Explanation: 
The graph looks like this:
0----1
| \  |
|  \ |
3----2
We cannot find a way to divide the set of nodes into two independent subsets.

Note:
  • graph will have length in range [1, 100].
  • graph[i] will contain integers in range [0, graph.length - 1].
  • graph[i] will not contain i or duplicate values.
  • The graph is undirected: if any element j is in graph[i], then i will be in graph[j].
--------------------------
垂直一条线把graph分为2半,每一半的node只能有链接通向对面一半,不能跟相同一半的node有链接。

把2半分别标记别true跟false

Solution #1 DFS
class Solution {
    public boolean isBipartite(int[][] graph) {
        Map<Integer, Boolean> map = new HashMap<>();
        for (int i = 0; i < graph.length; i++) {
            if (!map.containsKey(i) && !dfs(map, graph, i, true)) return false;
        }
        
        return true;
    }
    
    private boolean dfs(Map<Integer, Boolean> map, int[][] graph, int node, boolean flag) {
        if (map.containsKey(node) && map.get(node) == flag) return false;
        if (map.containsKey(node)) return true;
        
        map.put(node, !flag);
        for (int neighbor : graph[node]) {
            if (!dfs(map, graph, neighbor, !flag)) return false;
        }
        
        return true;
    }
}

Solution #2 BFS
class Solution {
    
    public boolean isBipartite(int[][] graph) {
        Map map = new HashMap<>();
        for (int i = 0; i < graph.length; i++) {
            if (!map.containsKey(i) && !bfs(map, graph, i)) return false;
        }
        
        return true;
    }
    
    private boolean bfs(Map map, int[][] graph, int node) {
        
        Queue que = new LinkedList<>();
        
        que.add(node);
        map.put(node, true);
        
        while (!que.isEmpty()) {
            int top = que.poll();
            for (int neighbor : graph[top]) {
                if (!map.containsKey(neighbor)) {
                    que.add(neighbor);
                    map.put(neighbor, !map.get(top));
                }else if (map.containsKey(neighbor) && map.get(neighbor) == map.get(top)) {
                    return false;
                }
            }
        }
        
        return true;
    }
    
}

Saturday, July 21, 2018

286. Walls and Gates

Walls and Gates
You are given a m x n 2D grid initialized with these three possible values.
  1. -1 - A wall or an obstacle.
  2. 0 - A gate.
  3. INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.
Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.
Example: 
Given the 2D grid:
INF  -1  0  INF
INF INF INF  -1
INF  -1 INF  -1
  0  -1 INF INF
After running your function, the 2D grid should be:
  3  -1   0   1
  2   2   1  -1
  1  -1   2  -1
  0  -1   3   4

------------------------------
典型的BFS,注意的是需要从所有0的位置同时开始走
O(m * n), m n 为2维数组的长宽。因为一个INF的点最多只被走一次
class Solution {

    public void wallsAndGates(int[][] rooms) {
        Queue<Pair> que = getQueue(rooms);
        
        fillRooms(rooms, que);
    }
    
    private void fillRooms(int[][] rooms, Queue<Pair> que) {
        
        int[][] coord = {{1,0}, {-1,0}, {0,1}, {0,-1}};
        
        while (!que.isEmpty()) {
            
            Pair top = que.poll();
            for (int[] arr : coord) {
                int r = top.row + arr[0];
                int c = top.col + arr[1];
                
                if (r >= 0 && r < rooms.length && c >= 0 && c < rooms[0].length
                   && rooms[r][c] == 2147483647) {
                    rooms[r][c] = rooms[top.row][top.col] + 1;
                    que.add(new Pair(r, c));
                }
            }
        }
    }
    
    private Queue<Pair> getQueue(int[][] rooms) {
        Queue<Pair> que = new LinkedList<>();
        
        for (int i = 0; i < rooms.length; i++) {
            for (int j = 0; j < rooms[0].length; j++) {
                if (rooms[i][j] == 0) {
                    que.add(new Pair(i, j));
                }
            }
        }
        
        return que;
    }
}

class Pair{
    public int row;
    public int col;
    public Pair(int row, int col) {
        this.row = row;
        this.col = col;
    }
}

Thursday, July 19, 2018

494. Target Sum

494Target Sum
You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.
Find out how many ways to assign symbols to make sum of integers equal to target S.
Example 1:
Input: nums is [1, 1, 1, 1, 1], S is 3. 
Output: 5
Explanation: 

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

There are 5 ways to assign symbols to make the sum of nums be target 3.
Note:
  1. The length of the given array is positive and will not exceed 20.
  2. The sum of elements in the given array will not exceed 1000.
  3. Your output answer is guaranteed to be fitted in a 32-bit integer.
---------------------------
Solution #1, straightforward recursion
O(2^n)
class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        return helper(nums, 0, S);
    }
    
    private int helper(int[] nums, int index, int sum) {
        if (index == nums.length && sum == 0) return 1;
        if (index >= nums.length) return 0;
        
        return helper(nums, index + 1, sum - nums[index]) 
            + helper(nums, index + 1, sum + nums[index]);
    }
}
Solution #2
Memoization
会发现此题有重复的子问题,DP可解:
+ 1 - 1 [11] 跟 - 1 + 1 [11], 括号内为重复
+ 1 + 2 - 3 [4 5 6] 跟 - 1 - 2 + 3 [4 5 6]

很难直接从递归就看出它的复杂度,因为取决于生成不同sum的个数。树的深度为nums的长度
class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        return helper(nums, 0, S, new HashMap());
    }
    
    private int helper(int[] nums, int index, int sum, Map cache) {
        if (index == nums.length && sum == 0) return 1;
        if (index >= nums.length) return 0;
        
        String plusKey = index + "+" + sum;
        int plus = 0;
        if (cache.containsKey(plusKey)) {
            plus = cache.get(plusKey);
        } else {
            plus = helper(nums, index + 1, sum - nums[index], cache);    
            cache.put(plusKey, plus);
        }
        
        String minusKey = index + "-" + sum;
        int minus = 0;
        if (cache.containsKey(minusKey)) {
            minus = cache.get(minusKey);
        } else {
            minus = helper(nums, index + 1, sum + nums[index], cache);   
            cache.put(minusKey, minus);
        }        
        
        return plus + minus;
    }
}
Solution #3,遍历DP,跟上面Memoization一样,每一个小问题都可以用(index, sum)的组合来表示
O(n * m) 时间,n为nums的changdu,m为最长的sums的可能性
class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int n = nums.length;
        Map sums = new HashMap<>();
        Map newSums = new HashMap<>();
        sums.put(S, 1);
        
        for (int i = n - 1; i >= 0; i--) {
            int num = nums[i];
            
            for (Map.Entry pair : sums.entrySet()) {
                int sum1 = pair.getKey() - num;
                addToNewMap(newSums, sum1, pair.getValue());
                
                int sum2 = pair.getKey() + num;
                addToNewMap(newSums, sum2, pair.getValue());
            }
            
            Map tmp = sums;
            sums.clear();
            sums = newSums;
            newSums = tmp;
        }
        
        return sums.getOrDefault(0, 0);
    }
    
    private void addToNewMap(Map cur, int sum, int value) {
        if (!cur.containsKey(sum)) {
            cur.put(sum, 0);
        }
        cur.put(sum, value + cur.get(sum));
    }
}

其他:因为题目已经给定所有数的sum不会超过1000,所以有一种方法是开一个大小为1000(?或者2000 + 1,因为要考虑0和负数)的数组,每次遍历一下就是了。
但是以上我的方法不会被1000所限制。

Update: 发现Solution #2-#3原来就是所谓的subset sum

Wednesday, July 18, 2018

825. Friends Of Appropriate Ages

825Friends Of Appropriate Ages
Some people will make friend requests. The list of their ages is given and ages[i] is the age of the ith person. 
Person A will NOT friend request person B (B != A) if any of the following conditions are true:
  • age[B] <= 0.5 * age[A] + 7
  • age[B] > age[A]
  • age[B] > 100 && age[A] < 100
Otherwise, A will friend request B.
Note that if A requests B, B does not necessarily request A.  Also, people will not friend request themselves.
How many total friend requests are made?
Example 1:
Input: [16,16]
Output: 2
Explanation: 2 people friend request each other.
Example 2:
Input: [16,17,18]
Output: 2
Explanation: Friend requests are made 17 -> 16, 18 -> 17.
Example 3:
Input: [20,30,100,110,120]
Output: 
Explanation: Friend requests are made 110 -> 100, 120 -> 110, 120 -> 100.

Notes:
  • 1 <= ages.length <= 20000.
  • 1 <= ages[i] <= 120.
--------------------------
按年龄大小排序,O(n) time, O(1) space. 因为年龄是有限的1-120
题目中第3个条件是多余的
class Solution {
    public int numFriendRequests(int[] ages) {
        int[] ageMap = new int[121];
        
        for (int age : ages) {
            ageMap[age]++;
        }
        
        int rt = 0;
        
        for (int i = 120; i > 0; i--) {
            if (ageMap[i] == 0) continue;
            int cutOff = (int)(0.5 * i + 7) + 1;
            if (cutOff > i) continue;
            
            int cutOffNum = 0;
            for (int j = cutOff; j < i; j++) {
                cutOffNum += ageMap[j];
            }
            
            rt += cutOffNum * ageMap[i] + (ageMap[i] - 1) * ageMap[i];
        }
        
        return rt;
    }
}

Monday, July 16, 2018

523, 49 Continuous Subarray Sum, Group Anagrams

 523Continuous Subarray Sum
Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous subarray of size at least 2 that sums up to the multiple of k, that is, sums up to n*k where n is also an integer.
Example 1:
Input: [23, 2, 4, 6, 7],  k=6
Output: True
Explanation: Because [2, 4] is a continuous subarray of size 2 and sums up to 6.
Example 2:
Input: [23, 2, 6, 4, 7],  k=6
Output: True
Explanation: Because [23, 2, 6, 4, 7] is an continuous subarray of size 5 and sums up to 42.
Note:
  1. The length of the array won't exceed 10,000.
  2. You may assume the sum of all the numbers is in the range of a signed 32-bit integer.
--------------------
HashMap 存Sum -> index
注意各种corner cases: n可以为非正数,array有相邻2个0存在,当sum为0时要检查subarray长度

如果改变题目要求,找sum为k,也是同样类似思路
class Solution {
    public boolean checkSubarraySum(int[] nums, int k) {
        if (nums == null || nums.length < 2) return false;
        if (checkZeros(nums)) return true;
        if (k == 0) return false;
        
        Map<Integer, Integer> map = new HashMap<>();
        int sum = 0;
        
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            sum %= k;
            if ((map.containsKey(sum) && i - map.get(sum) > 0)
                || (i > 0 && sum == 0)) {
                return true;
            }
            map.put(sum, i);
        }
        
        return false;
    }
    
    private boolean checkZeros(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] == 0 && nums[i - 1] == 0) return true;
        }
        
        return false;
    }
}

49Group Anagrams
Given an array of strings, group anagrams together.
Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
Note:
  • All inputs will be in lowercase.
  • The order of your output does not matter.
----------------------
Solution #1, 把每个string都排序一下(其实也就是编码),同一个Anagram的都会有一个相同的编码
时间O(n * klog(k)), n为strs的长度,k为其中string的平均长度 空间O(n * k)
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        
        Map<String, List<String>> map = new HashMap<>();
        
        for (String s : strs) {
            char[] sorted = s.toCharArray();
            Arrays.sort(sorted);
            String st = new String(sorted);
            if (!map.containsKey(st)) {
                map.put(st, new ArrayList<>());
            }
            map.get(st).add(s);
        }
        
        return new ArrayList<>(map.values());
    }
}

Solution #2, 换一种方法来编码,线性
O(n * k) time complexity, n是strs的changdu,k是其中string的平均长度
空间O(n * k)
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<>();
        
        for (String s : strs) {
            String encoding = getEncoding(s);
            if (!map.containsKey(encoding)) {
                map.put(encoding, new ArrayList<>());
            }
            map.get(encoding).add(s);
        }
        
        return new ArrayList<>(map.values());
    }
    
    private String getEncoding(String s) {
        int[] m = new int[26];
        
        for (int i = 0; i < s.length(); i++) {
            m[s.charAt(i) - 'a']++;
        }
        
        StringBuilder rt = new StringBuilder();
        for (int i = 0; i < 26; i++) {
            int c = m[i] + 'a';
            rt.append(c).append(",");
        }
        
        return rt.toString();
    }
}

Friday, July 13, 2018

670 Maximum Swap

Maximum Swap
Given a non-negative integer, you could swap two digits at most once to get the maximum valued number. Return the maximum valued number you could get.
Example 1:
Input: 2736
Output: 7236
Explanation: Swap the number 2 and the number 7.
Example 2:
Input: 9973
Output: 9973
Explanation: No swap.
Note:
  1. The given number is in the range [0, 108]
-------------------------------------
Solution #1, 所有上升的数字都有可能被换到前面,拐点之前下降的则不会。找拐点之后最大的往前换,如果有相同的则取index靠后的。
9872345, 2为拐点,987不可能往前换,345则可能往前换
654123439,1为拐点,23439中最大的9可以往前换
class Solution {
    public int maximumSwap(int num) {
        char[] A = Integer.toString(num).toCharArray();
        
        int i = 1;
        for (; i < A.length; i++) {
            if (A[i] > A[i - 1]) break;
        }
        
        int max = -1;
        for (; i < A.length; i++) {
            if (max == -1 || A[max] - '0' <= A[i] - '0') {
                max = i;
            }
        }
        
        if (max == -1) return num;
        
        for (int j = 0; j < A.length; j++) {
            if (A[j] < A[max]) {
                char temp = A[j];
                A[j] = A[max];
                A[max] = temp;
                return Integer.valueOf(new String(A));
            }
        }
        
        return num;
    }
}

Solution #2, 把0-9每个数的位置预先存上,再从左遍历原数字,如果发现它右方有数字比它大,则进行交换,返回结果
class Solution {
    public int maximumSwap(int num) {
        char[] A = Integer.toString(num).toCharArray();
        int[] pos = new int[10];
        
        for (int i = 0; i < A.length; i++) {
            char c = A[i];
            pos[c - '0']  = i;
        }
        
        for (int i = 0; i < A.length; i++) {
            int val = A[i] - '0';
            for (int j = 9; j > 0; j--) {
                if (val >= j) break;
                if (pos[j] > i) {
                    char temp = A[pos[j]];
                    A[pos[j]] = A[i];
                    A[i] = temp;
                    return Integer.valueOf(new String(A));
                }
            }
        }
        
        return num;
    }
}

Sunday, July 8, 2018

642 Design Search Autocomplete System

Design Search Autocomplete System
Design a search autocomplete system for a search engine. Users may input a sentence (at least one word and end with a special character '#'). For each character they type except '#', you need to return the top 3 historical hot sentences that have prefix the same as the part of sentence already typed. Here are the specific rules:
  1. The hot degree for a sentence is defined as the number of times a user typed the exactly same sentence before.
  2. The returned top 3 hot sentences should be sorted by hot degree (The first is the hottest one). If several sentences have the same degree of hot, you need to use ASCII-code order (smaller one appears first).
  3. If less than 3 hot sentences exist, then just return as many as you can.
  4. When the input is a special character, it means the sentence ends, and in this case, you need to return an empty list.
Your job is to implement the following functions:
The constructor function:
AutocompleteSystem(String[] sentences, int[] times): This is the constructor. The input is historical dataSentences is a string array consists of previously typed sentences. Times is the corresponding times a sentence has been typed. Your system should record these historical data.
Now, the user wants to input a new sentence. The following function will provide the next character the user types:
List<String> input(char c): The input c is the next character typed by the user. The character will only be lower-case letters ('a' to 'z'), blank space (' ') or a special character ('#'). Also, the previously typed sentence should be recorded in your system. The output will be the top 3 historical hot sentences that have prefix the same as the part of sentence already typed.

Example:
Operation: AutocompleteSystem(["i love you", "island","ironman", "i love leetcode"], [5,3,2,2])
The system have already tracked down the following sentences and their corresponding times:
"i love you" : 5 times
"island" : 3 times
"ironman" : 2 times
"i love leetcode" : 2 times
Now, the user begins another search:

Operation: input('i')
Output: ["i love you", "island","i love leetcode"]
Explanation:
There are four sentences that have prefix "i". Among them, "ironman" and "i love leetcode" have same hot degree. Since ' ' has ASCII code 32 and 'r' has ASCII code 114, "i love leetcode" should be in front of "ironman". Also we only need to output top 3 hot sentences, so "ironman" will be ignored.

Operation: input(' ')
Output: ["i love you","i love leetcode"]
Explanation:
There are only two sentences that have prefix "i ".

Operation: input('a')
Output: []
Explanation:
There are no sentences that have prefix "i a".

Operation: input('#')
Output: []
Explanation:
The user finished the input, the sentence "i a" should be saved as a historical sentence in system. And the following input will be counted as a new search. 

Note:
  1. The input sentence will always start with a letter and end with '#', and only one blank space will exist between two words.
  2. The number of complete sentences that to be searched won't exceed 100. The length of each sentence including those in the historical data won't exceed 100.
  3. Please use double-quote instead of single-quote when you write test cases even for a character input.
  4. Please remember to RESET your class variables declared in class AutocompleteSystem, as static/class variables are persisted across multiple test cases. Please see here for more details.
-----------------------------------------

2个方法,
#1 用缓存,在每个结点把所有prefix 的string的个数都存上,每次返回前3就好
#2 不缓存。每次都重新计算
各有利弊空间vs时间,#1会占很大空间,#2会花很多时间,#2过不了Leetcode的OA

#1 AutocompleteSystem - O(k * n), k 为sentence的平均长度,n为sentence的个数
input - 每一次查找是O(1), sort是O(m * lg m), m为所对应的map的size
空间那就太不一定了
#2 AutocompleteSystem跟上面一样
input - 每一次查找是 O((26 + 1)^n), n为最长string的剩余长度

Solution #1
class AutocompleteSystem {
    
    private Node root;
    private Node current;
    private String sofar;
    public AutocompleteSystem(String[] sentences, int[] times) {
        root = new Node();
        current = root;
        sofar = "";
        
        for (int i = 0; i < sentences.length; i++) {
            String sentence = sentences[i];
            int count = times[i];
            
            addToMap(sentence, count);
        }
    }
    
    private void addToMap(String s, int count) {
        Node head = root;
        
        for (int j = 0; j < s.length(); j++) {
            char c = s.charAt(j);
            if (!head.next.containsKey(c)) {
                head.next.put(c, new Node());
            }

            Node cur = head.next.get(c);
            cur.map.put(s, cur.map.getOrDefault(s, 0) + count);
            head = cur;
        }
    }
    
    
    public List<String> input(char c) {
        if (c != '#') {
            sofar += c;
            if (current == null || !current.next.containsKey(c)) {
                current = null;
                return new ArrayList<String>();
            }
            
            current = current.next.get(c);
            return getOrdered(current.map);
            
        }else {
            addToMap(sofar, 1);
            sofar = "";
            current = root;
            return new ArrayList<>();
        }
    }
    
    private List<String> getOrdered(Map<String, Integer> map) {
        List<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
        Collections.sort(entries, (a, b) -> {
            if (a.getValue() == b.getValue()) return a.getKey().compareTo(b.getKey());
            return b.getValue() - a.getValue();
        });
        
        List<String> rt = new ArrayList<>();
        for (int i = 0; i < Math.min(3,entries.size()); i++) {
            rt.add(entries.get(i).getKey());
        }
        return rt;
    }
}

class Node {
    public Map<String, Integer> map;
    public Map<Character, Node> next;
    
    public Node () {
        map = new HashMap<>();
        next = new HashMap<>();        
    }
}

/**
 * Your AutocompleteSystem object will be instantiated and called as such:
 * AutocompleteSystem obj = new AutocompleteSystem(sentences, times);
 * List<String> param_1 = obj.input(c);
 */
Solution #2, 不进行缓存,每次都重新把tries走一遍。这个方法过不了OA
class AutocompleteSystem {
    class Node{
        public Map<Character, Node> next;
        public boolean isWord;
        public int count;
        
        public Node() {
            count = 0;
            next = new HashMap<>();
        }
    }
    
    class Pair{
        public String st;
        public int count;
        public Pair(String st, int count) {
            this.st = st;
            this.count = count;
        }
    }
    
    private Node root;
    private String sofar;
    private Node cur;

    public AutocompleteSystem(String[] sentences, int[] times) {
        
        root = new Node();
        sofar = "";
        
        for (int i = 0; i < sentences.length; i++) {
            addToSystem(sentences[i], times[i]);
        }
        
    }
    
    private void addToSystem(String sentence, int time) {
        Node node = root;
        
        for (int i = 0; i < sentence.length(); i++) {
            char c = sentence.charAt(i);
            if (!node.next.containsKey(c)) {
                node.next.put(c, new Node());        
            }
            
            node = node.next.get(c);
        }
        
        node.isWord = true;
        node.count += time;
    }
    
    public List<String> input(char c) {
        
        if (c == '#') {
            addToSystem(sofar, 1);
            sofar = "";
            return new ArrayList<>();
            
        }else {
            if (sofar.length() == 0) {
                cur = root;
            }
            sofar += c;
            if (!cur.next.containsKey(c)) {
                return new ArrayList<>();
            }
            
            cur = cur.next.get(c);
            List<Pair> rt = new ArrayList<>();
            computeCounts(rt, cur, sofar);
            
            Collections.sort(rt, (a, b) -> b.count - a.count);
            List<String> guess = new ArrayList<>();
            for (int i = 0; i < Math.min(3, rt.size()); i++) {
                guess.add(rt.get(i).st);
            }
            
            return guess;
        }
    }
    
    private void computeCounts(List<Pair> rt, Node node, String cur) {

        if (node.isWord) {
            rt.add(new Pair(cur, node.count));
        } 
        
        for (Map.Entry<Character, Node> entry : node.next.entrySet()) {
            String temp = cur + entry.getKey();
            computeCounts(rt, entry.getValue(), temp);
        }
    }
}

/**
 * Your AutocompleteSystem object will be instantiated and called as such:
 * AutocompleteSystem obj = new AutocompleteSystem(sentences, times);
 * List<String> param_1 = obj.input(c);
 */

Sunday, July 1, 2018

738 Monotone Increasing Digits

738Monotone Increasing Digits
Given a non-negative integer N, find the largest number that is less than or equal to N with monotone increasing digits.
(Recall that an integer has monotone increasing digits if and only if each pair of adjacent digits x and y satisfy x <= y.)
Example 1:
Input: N = 10
Output: 9
Example 2:
Input: N = 1234
Output: 1234
Example 3:
Input: N = 332
Output: 299
Note: N is an integer in the range [0, 10^9].
-----------------------------
重点是找到breakPoint, 多列几个test case就能明白怎么写了
7752 -> 6999
1541 -> 1499
85 -> 79
941 -> 899

分三步
1. 找到拐点
2. 拐点位置之前重新找拐点,新拐点位置之前所有值减1
3. 新拐点之后所有位置上的值为9

class Solution {
    public int monotoneIncreasingDigits(int N) {
        int[] arr = convertToArray(N);
        
        int i = getBreakPoint(arr);
        i = updateBeforeBreakPoint(arr, i);
        
        return getFinalNumber(arr, i);
    }
    
    private int getFinalNumber(int[] arr, int i) {
        int rt = 0;
        for (int j = 0; j < 9; j++) {
            if (j >= i + 1) {
                rt = 9 + rt * 10;
            }else if (arr[j] != 0) {
                rt = arr[j] + rt * 10;
            }
        }
        
        return rt;
    }
    
    private int updateBeforeBreakPoint(int[] arr, int i) {
        
        while (i > 0 && i < 9) {
            if (arr[i] >= arr[i - 1]) {
                break;   
            }
            arr[i - 1] = arr[i - 1] - 1;
            i--;
        }
        
        return i;
    }
    
    private int getBreakPoint(int[] arr) {
        
        int i = 1;
        while (i < 9) {
            if (arr[i] < arr[i - 1]) {
                break;
            }
            i++;
        }
        
        return i;
    }
    
    private int[] convertToArray(int N) {
        int[] arr = new int[9];
        
        for (int i = 8; i >= 0; i--) {
            arr[i] = N % 10;
            N /= 10;
        }
        
        return arr;
    }
}

流弊写法,从后往前
credit: barkfanleen3@gmail.com
class Solution {
    public int monotoneIncreasingDigits(int N) {
        int res = 0;
        int pre = Integer.MAX_VALUE;
        int offset =1;
        while(N != 0) {
            int digit = N % 10;
            if(digit > pre) {
                res = digit * offset - 1;
                pre = digit -1;
            }else {
                res = res + digit * offset;
                pre = digit;
            }
            offset *= 10;
            N = N/10;
        }
        return res;
    }
    
}