Sunday, September 30, 2018

792. Number of Matching Subsequences

二刷 07/2022
Version #2 List of words waiting for the next character
把所有的words分类成他们下一个需要match的character,如果在s里面遇到了这个character就把这些word取出来重新分类
这里space可以继续优化,就是不存每个word的string而是存word的index

Time O(L*N) - L is the length of string, N is the number of words?
Space O(MN) - total length of all words

Runtime: 119 ms, faster than 76.38% of Java online submissions for Number of Matching Subsequences.
Memory Usage: 118.8 MB, less than 10.36% of Java online submissions for Number of Matching Subsequences.
class Solution {
    public int numMatchingSubseq(String s, String[] words) {
        // use an array for words that are waiting for the next character
        List<Pair<String, Integer>>[] candidates = new ArrayList[26];
        for (int i = 0; i < 26; i++) {
            candidates[i] = new ArrayList<>();
        }
        for (String word : words) {
            candidates[word.charAt(0) - 'a'].add(new Pair<>(word, 0));
        }
        int result = 0;
        for (int i = 0; i < s.length(); i++) {
            List<Pair<String, Integer>> candidate = candidates[s.charAt(i) - 'a'];
            candidates[s.charAt(i) - 'a'] = new ArrayList<>();
            for (Pair<String, Integer> p : candidate) {
                String word = p.getKey();
                int nextPointer = p.getValue() + 1;
                if (nextPointer == word.length()) {
                    result++;
                    continue;
                }
                candidates[word.charAt(nextPointer) - 'a'].add(new Pair<>(word, nextPointer));
            } 
        }
        return result;
    }
}


Version #1 2D array for next occurrence
Time O(L + MN) - L is the string length, MN is the total length of all words
Space O(26L) ~ O(L)
Runtime: 215 ms, faster than 33.45% of Java online submissions for Number of Matching Subsequences.
Memory Usage: 119.5 MB, less than 7.67% of Java online submissions for Number of Matching Subsequences.
class Solution {
    public int numMatchingSubseq(String s, String[] words) {
        int[][] nextIndices = new int[s.length()][];
        int[] nextIndex = new int[26];
        Arrays.fill(nextIndex, -1);
        for (int i = s.length() - 1; i >= 0; i--) {
            nextIndices[i] = nextIndex.clone();
            nextIndex[s.charAt(i) - 'a'] = i;
        }
        int result = 0;
        for (String word: words) {
            int n = 0;
            int i = 0;
            for (i = 0; i < word.length(); i++) {
                if (i == 0) {
                    n = nextIndex[word.charAt(i) - 'a'];
                } else {
                    n = nextIndices[n][word.charAt(i) - 'a'];
                }
                if (n == -1) {
                    break;
                }
            }
            if (i == word.length()) {
                result++;
            }
        }
        return result;
    }


一刷
Version #1 Mem 2D array of next occurrence

39.72 %
class Solution {
    public int numMatchingSubseq(String S, String[] words) {
        char[] chars = S.toCharArray();
        int[][] mem = new int[chars.length][26];
        int length = chars.length;
       
        Arrays.fill(mem[length - 1], -1);
        for (int k = chars.length - 2; k >= 0; k--) {
            char c = chars[k + 1];
            for (int i = 0; i < 26; i++) {
                if (i == c - 'a') {
                    mem[k][i] = k + 1;
                } else {
                    mem[k][i] = mem[k + 1][i];
                }
            }
        }
       
       
       
        int count = 0;
        for (String word : words) {
            int pointer = 0;
            if (word.charAt(0) == chars[0]) {
                pointer = -1;
            } else {
                pointer = mem[0][word.charAt(0) - 'a'];
            }
            int i = 0;
            for (i = 1; i < word.length(); i++) {
                char curr = word.charAt(i);
                int next = 0;
                if (pointer == -1) {
                    next = mem[0][curr - 'a'];
                } else {
                    next = mem[pointer][curr - 'a'];
                }
                if (next == -1) {
                    break;
                }
                pointer = next;
            }
            if (i == word.length()) {
                count++;
            }
        }
        return count;
    }
}

911. Online Election

Version #2 Binary Search [TODO]


Version #1 TreeMap
Map + TreeMap
O(nlog) for initialization, O(logn) for query
62.40 %
class TopVotedCandidate {
    private TreeMap<Integer, Integer> map;
    public TopVotedCandidate(int[] persons, int[] times) {
        int max = 0;
        // k -> time, v -> maxPerson
        map = new TreeMap<>();
        // k -> person, v -> votes
        Map<Integer, Integer> votes = new HashMap<>();
        for (int i = 0; i < persons.length; i++) {
            int vote4Person = votes.getOrDefault(persons[i], 0) + 1;
            if (vote4Person >= max) {
                max = vote4Person;
                map.put(times[i], persons[i]);
            }
            votes.put(persons[i], vote4Person);
        }
    }
   
    public int q(int t) {
        return map.floorEntry(t).getValue();
    }
}

Sunday, September 23, 2018

909. Snakes and Ladders

Version #1 BFS

[[1,1,-1],[1,1,1],[-1,1,1]]
[[-1,-1,2,21,-1],[16,-1,24,-1,4],[2,3,-1,-1,-1],[-1,11,23,18,-1],[-1,-1,-1,23,-1]]
[[-1,-1,-1],[-1,9,8],[-1,8,9]]
[[1,1,-1],[1,1,1],[-1,1,1]]
[[-1,-1,27,13,-1,25,-1],[-1,-1,-1,-1,-1,-1,-1],[44,-1,8,-1,-1,2,-1],[-1,30,-1,-1,-1,-1,-1],[3,-1,20,-1,46,6,-1],[-1,-1,-1,-1,-1,-1,29],[-1,29,21,33,-1,-1,-1]]
[[-1,-1,-1,46,47,-1,-1,-1],[51,-1,-1,63,-1,31,21,-1],[-1,-1,26,-1,-1,38,-1,-1],[-1,-1,11,-1,14,23,56,57],[11,-1,-1,-1,49,36,-1,48],[-1,-1,-1,33,56,-1,57,21],[-1,-1,-1,-1,-1,-1,2,-1],[-1,-1,-1,8,3,-1,6,56]]

二刷
关键是把id转换成x,y需要多加注意

33.75 %
class Solution {
    private int rows, cols;
    public int snakesAndLadders(int[][] board) {
        this.rows = board.length;
        this.cols = board[0].length;
        int maxId = rows * cols;
        if (maxId == 1) {
            return board[0][0] == -1 ? 0 : -1;
        }
        Queue<Integer> que = new LinkedList<>();
        Set<Integer> visited = new HashSet<>();
        que.offer(1);
        int level = 0;
        while (!que.isEmpty()) {
            int size = que.size();
            level++;
            while (size-- > 0) {
                int curr = que.poll();
                for (int i = 1; i <= 6; i++) {
                    int next = curr + i;
                    int[] nextPos = getPos(next);
                    if (board[nextPos[1]][nextPos[0]] != -1) {
                        next = board[nextPos[1]][nextPos[0]];
                    }
                    if (next == maxId) return level;
                    if (visited.add(next)) {
                        que.offer(next);
                    }
                }
            }
        }
        return -1;
    }
   
    private int[] getPos(int id) {
        // e.g. rows = 6, cols = 6, id = 17
        // y = 5 - 2 = 3, x = 4
        int y = rows - 1 - (id - 1) / rows;
        int x = ((id - 1) / rows) % 2 == 0  ? (id - 1) % cols : cols - 1 - (id - 1) % cols;
        return new int[]{x, y};
    }
}

一刷
踩到一个坑里,de了一晚上
如果比如2的board value是29,那么就没有办法通过一步到达2,只有等到譬如34的board value是2的时候才可能到达2
所以2的Step数是到达34 的Step+1
class Solution {
    public int snakesAndLadders(int[][] board) {
        int rows = board.length;
        int cols = board[0].length;
        Queue<Integer> que = new LinkedList<>();
        Set<Integer> visited = new HashSet<>();
        que.offer(1);
        visited.add(1);
        int step = 0;
        while (!que.isEmpty()) {
            int size = que.size();
            step++;
            while (size-- > 0) {
                int curr = que.poll();
                for (int k = 1; k <= 6; k++) {
                    int next = curr + k;
                    int value = getValue(next, board);
                    if (value != -1) {
                        next = value;
                    }
                    if (next == rows * cols) {
                        return step;
                    }
                    if (visited.contains(next)) {
                        continue;
                    }
                    que.offer(next);
                    visited.add(next);
                }
             
            }
        }
     
        return -1;
    }
 
    private int getValue(int S, int[][] board) {
        int rows = board.length;
        int cols = board[0].length;
        S--;
        int x = rows - 1 - S / cols;
        int y = (S / cols % 2) == 0 ? S % cols : cols - 1 - S % cols;
        return board[x][y];
    }
}

Wednesday, September 19, 2018

159. Longest Substring with At Most Two Distinct Characters

三刷 07/2022
Version #2 Array as map + Sliding Window
一开始写了一个bug,就是当character count数大于2的时候,完全remove 左边界start的所有character
这种遇到反例abaccc的时候,不需要完全消除a就可以消除b了
所以start要一步一步往前走
这个做法是记录了the index of the last occurrence of the character,如果记录count of the character也是一样的

Time O(N)
Space O(256) ~ O(1)

Runtime: 15 ms, faster than 91.66% of Java online submissions for Longest Substring with At Most Two Distinct Characters.
Memory Usage: 47.3 MB, less than 81.26% of Java online submissions for Longest Substring with At Most Two Distinct Characters.
class Solution {
    public int lengthOfLongestSubstringTwoDistinct(String s) {
        // key is the ascii number of the character, value is the last index of that character
        int[] map = new int[126];
        int len = 0;
        Arrays.fill(map, -1);
        int count = 0; // number of distinct characters in the sliding window
        int start = 0;
        for (int end = 0; end < s.length(); end++) {
            char c = s.charAt(end);
            if (map[c] < start) { // this is a new character
                count++;
            }
            map[c] = end; // update the last occurance
            while (count > 2) {
                if (map[s.charAt(start)] == start) {
                    count--;
                }
                start++;
            }
            len = Math.max(len, end - start + 1);
        }
        return len;
    }
}


Version #1 HashMap + Sliding Window
Time O(n)

二刷
48.56 %
class Solution {
    public int lengthOfLongestSubstringTwoDistinct(String s) {
        // key->char, value->count of char
        Map<Character, Integer> map = new HashMap<>();
        // (left, right]
        int left = -1;
        int right = 0;
        int count = 2;
        int max = 0;
        for (right = 0; right < s.length(); right++) {
            char r = s.charAt(right);
            int rCount = map.getOrDefault(r, 0);
            if (rCount == 0) {
                count--;
            }
            map.put(r, rCount + 1);
            while (count < 0 && ++left < right) {
                char l = s.charAt(left);
                int lCount = map.getOrDefault(l, 0);
                lCount--;
                if (lCount <= 0) {
                    count++;
                }
                map.put(l, lCount);
            }
            max = Math.max(max, right - left);
        }
        return max;
    }
}

Version #2 lasOccurance
一刷
Time O(kN)
10.00 %
class Solution {
    public int lengthOfLongestSubstringTwoDistinct(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        // key->char, value->last occurance index
        Map<Character, Integer> map = new HashMap<>();
        // (left, right]
        int left = -1;
        int right = 0;
        int max = 0;
        for (right = 0; right < s.length(); right++) {
            map.put(s.charAt(right), right);
            if (map.size() > 2) {
                int index = Collections.min(map.values());
                map.remove(s.charAt(index));
                left = index;
            }
            max = Math.max(max, right - left);
        }
        return max;
    }
}

Sunday, September 16, 2018

904. Fruit Into Baskets


Version #3 Two Pointers
Time O(n)

38.04 %
class Solution {
    public int totalFruit(int[] tree) {
// (left, right] is a valid subarray that only contains at most two kinds of fruits
// key-fruit id, value-count
Map<Integer, Integer> map = new HashMap<>();
int max = 0;
int k = 2;
int left = -1, right = 0;
for (right = 0; right < tree.length; right++) {
int count = map.getOrDefault(tree[right], 0);
if (count == 0) k--; // a new type of fruit added
map.put(tree[right], count + 1);
while (k < 0) {
left++;
count = map.getOrDefault(tree[left], 0) - 1;
if (count == 0) k++; // this type of fruit is totally removed
map.put(tree[left], count);
}
// k == 0
max = Math.max(max, right - left);
}
return max;
}
}



Version #2 LinkedHashMap
Time O(n)
public int totalFruit(int[] tree) {
        if (tree == null) {
            return 0;
        }
        int maxLength = 0;
        FruitLinkedHashMap<Integer, Integer> map = new FruitLinkedHashMap<>(16, .75f, true, 3);
        map.put(-1, -1);
        for (int i = 0; i < tree.length; i++) {
            map.put(tree[i], i);
            try {
                maxLength = Math.max(maxLength, map.getLastViaReflection() - map.getFirstViaReflection());
            } catch (Exception e) {
                return 0;
            }
        }
        return maxLength;
    }
Helper class:
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;

class FruitLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
    private final int MAX_ENTRIES;

    public FruitLinkedHashMap(
            int initialCapacity, float loadFactor, boolean accessOrder, int maxEntries) {
        super(initialCapacity, loadFactor, accessOrder);
        this.MAX_ENTRIES = maxEntries;
    }
    @Override
    public boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }

    public V getFirstViaReflection() throws NoSuchFieldException, IllegalAccessException {
        Field head = LinkedHashMap.class.getDeclaredField("head");
        head.setAccessible(true);
        return ((Map.Entry<K, V>)head.get(this)).getValue();
    }

    public V getLastViaReflection() throws NoSuchFieldException, IllegalAccessException {
        Field tail = LinkedHashMap.class.getDeclaredField("tail");
        tail.setAccessible(true);
        return ((Map.Entry<K, V>)tail.get(this)).getValue();
    }
}


Version #1 HashMap LastOccurance
Time O(kn)

class Solution {
    public int totalFruit(int[] tree) {
        // Find the longest sub array [start, end] that only has 2 kinds of fruits
        if (tree == null || tree.length == 0) {
            return 0;
        }
        int result = 0;
        int start = 0, end = 0;
        // key -> fruit id, value -> index of last occurance
        Map<Integer, Integer> lastOccurance = new HashMap<>();
        for (end = 0; end < tree.length; end++) {
            lastOccurance.put(tree[end], end);
            if (lastOccurance.size() > 2) {
                start = 1 + lastOccurance.remove(tree[Collections.min(lastOccurance.values())]);
            }
            result = Math.max(result, end - start + 1);
        }
        return result;
    }
}

724. Find Pivot Index

二刷
Version #1 2 Passes
Time O(N)
Space O(1)
Runtime: 2 ms, faster than 78.73% of Java online submissions for Find Pivot Index.
Memory Usage: 51.6 MB, less than 82.34% of Java online submissions for Find Pivot Index.
class Solution {
    public int pivotIndex(int[] nums) {
        int right = 0;
        for (int num : nums) {
            right += num;
        }
        int left = 0;
        for (int i = 0; i < nums.length; i++) {
            right -= nums[i];
            if (left == right) {
                return i;
            }
            left += nums[i];
        }
        return -1;
    }
}



一刷
第一个想法是双指针从左右分别扫,谁的sum小就多移动一个
但是对于负数的case 是不成立的
看的答案,改成先求sum,然后从左扫到右

bug
Input:[-1,-1,-1,0,1,1]
Output:-1
Expected:0

 0 也能算是pivot...

47.09 %
class Solution {
    public int pivotIndex(int[] nums) {
        if (nums == null) {
            return -1;
        }
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        int leftSum = 0;
        for (int i = 0; i < nums.length; i++) {
            if (leftSum == sum - nums[i] - leftSum) {
                return i;
            }
            leftSum += nums[i];
        }
        return -1;
    }
}

436. Find Right Interval



Version #1 TreeMap
Key -> start, Value -> index


20.82 %

import java.util.Optional;
class Solution {
    public int[] findRightInterval(Interval[] intervals) {
        if (intervals == null) {
            return null;
        }
        TreeMap<Integer, Integer> treeMap = new TreeMap<>();
        for (int i = 0; i < intervals.length; i++) {
            treeMap.put(intervals[i].start, i);
        }
        return IntStream.range(0, intervals.length)
            .map(i -> Optional.ofNullable(treeMap.ceilingEntry(intervals[i].end))
                 .map(entry -> entry.getValue())
                 .orElseGet(() -> -1)
                )
            .toArray();
    }
}

201. Bitwise AND of Numbers Range

二刷 07/2022
Version #2 Turn off the right most bit of the larger number
Time O(1)
Space O(1)
Runtime: 7 ms, faster than 85.09% of Java online submissions for Bitwise AND of Numbers Range.
Memory Usage: 44.5 MB, less than 25.77% of Java online submissions for Bitwise AND of Numbers Range.

class Solution {
    public int rangeBitwiseAnd(int left, int right) {
        while (left < right) {
            right = right & (right - 1);
        }
        return left & right;
    }
}


Ref: https://www.cnblogs.com/grandyang/p/4431646.html
一刷
// Find the common prefix of m and n
100.00 %
class Solution {
    public int rangeBitwiseAnd(int m, int n) {
        int bit = 0;
        while ((m >> bit) != (n >> bit)) {
            bit++;
        }
        return (m >> bit) << bit;
    }
}


290. Word Pattern

二刷 06/2022
Version #1 Map + Set
一刷的map.containsValue应该是O(N)的complexity
同时如果用s.split("\\s+")就会非常慢
由于题目已经说了是devided by single space,所以可以直接s.split(" ")
Time O(N)
Space O(M) ~ O(1) Since M is at most 26

Runtime: 1 ms, faster than 97.13% of Java online submissions for Word Pattern.
Memory Usage: 42 MB, less than 47.49% of Java online submissions for Word Pattern.
class Solution {
    public boolean wordPattern(String pattern, String s) {
        String[] words = s.split(" ");
        if (pattern.length() != words.length) {
            return false;
        }
        Map<Character, String> map = new HashMap<>();
        Set<String> wordSet = new HashSet<>();
        for (int i = 0; i < pattern.length(); i++) {
            char p = pattern.charAt(i);
            if (map.containsKey(p)) {
                if (!words[i].equals(map.get(p))) {
                    return false;
                }
            } else {
                if (wordSet.contains(words[i])) {
                    return false;
                }
                map.put(p, words[i]);
                wordSet.add(words[i]);
            }
        }
        return true;
    }
}

一刷
Version #1 Map from pattern char to word string
Time O(n^2)
Space O(n)
29.13 %
key is check if map containsValue(words[i]) to avoid multiple patern character map th the same word
class Solution {
    public boolean wordPattern(String pattern, String str) {
        if (pattern == null || str == null) {
            return false;
        }
        String[] words = str.split("\\s+");
        if (pattern.length() != words.length) {
            return false;
        }
        Map<Character, String> map = new HashMap<>();
        for (int i = 0; i < pattern.length(); i++) {
            char c = pattern.charAt(i);
            if (map.containsKey(c)) {
                if (!map.get(c).equals(words[i])) {
                    return false;
                }
            } else {
                if (map.containsValue(words[i])) {
                    return false;
                }
                map.put(c, words[i]);
            }
        }
        return true;
    }
}

Thursday, September 13, 2018

890. Find and Replace Pattern

[TODO] Version #4 Use 1 Map

二刷 07/2022
Version #3 2 Arrays as HashMaps
Time O(MN)
Space O(1)
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find and Replace Pattern.
Memory Usage: 43 MB, less than 57.14% of Java online submissions for Find and Replace Pattern.

class Solution {
    public List<String> findAndReplacePattern(String[] words, String pattern) {
        List<String> result = new ArrayList<>();
        for (String word : words) {
            if (isMatch(word, pattern)) {
                result.add(word);
            }
        }
        return result;
    }
    
    private boolean isMatch(String word, String pattern) {
        if (word.length() != pattern.length()) {
            return false;
        }
        char[] wordToPattern = new char[26];
        boolean[] usedPattern = new boolean[26];
        for (int i = 0; i < word.length(); i++) {
            char wc = word.charAt(i);
            char pc = pattern.charAt(i);
            if (wordToPattern[wc - 'a'] == 0) {
                if (usedPattern[pc - 'a']) {
                    return false;
                }
                wordToPattern[wc - 'a'] = pc;
                usedPattern[pc - 'a'] = true;
                continue;
            }
            if (wordToPattern[wc - 'a'] != pc) {
                return false;
            }
        }
        return true;
    }
}


一刷
Version #2 Counter
The mapping relationship is bi-direction so I have actually two maps


 100.00 %
class Solution {
    public List<String> findAndReplacePattern(String[] words, String pattern) {
        List<String> result = new ArrayList<>();
        char[] patternArray = pattern.toCharArray();
        for (String word : words) {
            if (isMatch(word.toCharArray(), patternArray)) {
                result.add(word);
            }
        }
        return result;
    }
   
    private boolean isMatch(char[] word, char[] pattern) {
        if (word.length != pattern.length) {
            return false;
        }
        char[] word2Pat = new char[256];
        char[] pat2Word = new char[256]; 
        for (int i = 0; i < word.length; i++) {
            if (word2Pat[word[i]] == 0) {
                if (pat2Word[pattern[i]] == 0) {
                    word2Pat[word[i]] = pattern[i];
                    pat2Word[pattern[i]] = word[i];
                } else {
                    return false;
                }
            } else if (word2Pat[word[i]] != pattern[i]) {
                return false;
            }
        }
        return true;
    }
}


Version #1 Normalize word
Use the index of first occurrence as id of the character
Kind of like hashing

Stream version
Beats 0%

class Solution {
    public List<String> findAndReplacePattern(String[] words, String pattern) {
        if (words == null || words.length == 0 || pattern == null) {
            return null;
        }
        Integer[] target = normalize(pattern);
        return Arrays.stream(words)
            .filter(word -> Arrays.equals(normalize(word), target))
            .collect(Collectors.toList());
    }
    private Integer[] normalize(String word) {
        Map<Character, Integer> idMap = new HashMap<>();
        // Use the index of first occurance as id of the character
        return word.chars().mapToObj(i -> (char) i)
            .map(c -> {
                Integer id = idMap.get(c);
                if (id == null) {
                    id = idMap.size();
                    idMap.put(c, id);
                }
                return id;
            }).toArray(size -> new Integer[size]);
    }
}

604. Design Compressed String Iterator

char to number不能用Integer.valueOf()
应该用 char - '0'

21.75 %
class StringIterator {
    char[] chars;
    char curr;
    int count;
    int pointer;
    public StringIterator(String compressedString) {
        this.chars = compressedString.toCharArray();
        count = 0;
        pointer = 0;
    }
   
    public char next() {
        char result;
        if (hasNext()) {
            count--;
            result = curr;
        } else {
            result = ' ';
        }
        return result;
    }
   
    public boolean hasNext() {
        if (count != 0) {
            return true;
        }
        if (pointer == chars.length) {
            return false;
        }
        curr = chars[pointer++];
        while (pointer < chars.length && Character.isDigit(chars[pointer])) {
            count = count * 10 + chars[pointer] - '0';
            pointer++;
        }
        return count != 0;
    }
}

Wednesday, September 12, 2018

735. Asteroid Collision

三刷

91.91 %
class Solution {
    public int[] asteroidCollision(int[] asteroids) {
        Deque<Integer> stack = new ArrayDeque<>();
        for (int ast : asteroids) {
            if (ast > 0) {
                stack.push(ast);
            } else {
                while (!stack.isEmpty() && stack.peek() > 0 && stack.peek() < -ast) {
                    stack.pop();
                }
                if (!stack.isEmpty() && stack.peek() > 0 && stack.peek() == -ast) {
                    stack.pop();
                } else if (stack.isEmpty() || stack.peek() < 0) {
                    stack.push(ast);
                }
                // stack.peek() == -ast || stack.peek() > -ast will destroy ast
            }
        }
        int[] result = new int[stack.size()];
        for (int i = 0; i < result.length; i++) {
            result[i] = stack.removeLast();
        }
        return result;
    }
}

一刷

Better Version
12.90 %
class Solution {
    public int[] asteroidCollision(int[] asteroids) {
        if (asteroids == null || asteroids.length == 0) {
            return asteroids;
        }
        LinkedList<Integer> stack = new LinkedList<>();
        for (int asteroid : asteroids) {
            if (asteroid > 0 || stack.isEmpty() || stack.getLast() < 0) {
                stack.add(asteroid);
            } else {
                while (!stack.isEmpty() && stack.getLast() > 0 && stack.getLast() < -asteroid) {
                    stack.pollLast();
                }
                if (!stack.isEmpty() && stack.getLast() == -asteroid) {
                    stack.pollLast();
                } else if (stack.isEmpty() || stack.getLast() < 0) {
                    stack.add(asteroid);
                }
            }
        }
        return stack.stream().mapToInt(i -> i).toArray();
    }
}





52.98 %
class Solution {
    public int[] asteroidCollision(int[] asteroids) {
        if (asteroids == null || asteroids.length == 0) {
            return asteroids;
        }
        Stack<Integer> stack = new Stack<>();
        for (int asteroid : asteroids) {
            if (asteroid > 0) {
                stack.push(asteroid);
            } else {
                while(!stack.isEmpty() && stack.peek() > 0 && stack.peek() < -asteroid) {
                    stack.pop();
                }
                if (!stack.isEmpty() && stack.peek() == -asteroid) {
                    stack.pop();
                } else if (stack.isEmpty() || stack.peek() < 0 || stack.peek() < -asteroid) {
                    stack.push(asteroid);
                }
            }
        }
        int[] result = new int[stack.size()];
        for (int i = result.length - 1; i >= 0; i--) {
            result[i] = stack.pop();
        }
        return result;
    }
}

Sunday, September 9, 2018

897. Increasing Order Search Tree

Version #2 Iterative Version
二刷
Bug
MLE -> 一开始不知道咋回事,后来发现是一个edge case
   1
  /
2
由于我是prev.left = null
当root是最后一个点的时候,没有机会给prev.left设置成null
就会形成环

100.00 %
class Solution {
    public TreeNode increasingBST(TreeNode root) {
        if (root == null) {
            return root;
        }
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode prev = null;
        TreeNode curr = root;
        TreeNode head = null;
        while (curr != null || !stack.isEmpty()) {
            while (curr != null) {       
                stack.addFirst(curr);
                curr = curr.left;
            }
            curr = stack.removeFirst();
            if (head == null) {
                head = curr;
            }
            if (prev != null) {
                prev.right = curr;
                prev.left = null;
            }
            prev = curr;
            curr = curr.right;
        }
        prev.left = null;
        return head;
    }
}

一刷
64.21 %
class Solution {
    public TreeNode increasingBST(TreeNode root) {
        if (root == null) {
            return null;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode result = null;
        TreeNode prev = null;
        TreeNode curr = root;
        while (!stack.isEmpty() || curr != null) {
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
            curr = stack.pop();
            if (prev == null) {
                result = curr;
            } else {
                prev.right = curr;
            }
            prev = curr;
            curr.left = null;
            curr = curr.right;
        }
        return result;
    }
}



Version #1 Recursion
Key is the base case
When root == null, what should we return -> consider its parent node

22.36 %
class Solution {
    public TreeNode increasingBST(TreeNode root) {
        return helper(root, null);
    }
    // result = increasingBST(root.left) + root + increasingBST(root.right)
    // return the head node and connect the last node of result to tail
    private TreeNode helper(TreeNode root, TreeNode tail) {
        if (root == null) {
            return tail;
        }
        TreeNode result = helper(root.left, root);
        root.left = null;
        root.right = helper(root.right, tail);
        return result;
    }
}

Saturday, September 8, 2018

901. Online Stock Span

Version #2 Binary Search
Time O(logn)

class StockSpanner {
    // int[0] -> the minimum stock price needed to connect to current range
    // int[1] -> the length of current range
    // int[2] -> index of the first price in current range
    List<int[]> minRange;
    int lastIndex;
    int count;
 
    public StockSpanner() {
        this.minRange = new ArrayList<>();
        this.lastIndex = -1;
        this.count = 0;
    }
 
    public int next(int price) {
        int start = 0;
        int end = lastIndex;
        while (start < end) {
            int mid = start + (end - start) / 2;
            if (minRange.get(mid)[0] > price) {
                start = mid + 1;
            } else {
                end = mid;
            }
        }
        int result = 0;
        if (minRange.size() == 0 || minRange.get(start)[0] > price) {
            result = 1;
            insert(lastIndex + 1, new int[]{price, result, count});
        } else {
            result = count - minRange.get(start)[2] + 1;
            insert(start, new int[]{price, result, minRange.get(start)[2]});
        }
        count++;
        return result;
    }
 
    private void insert(int index, int[] value) {
        if (index == minRange.size()) {
            minRange.add(value);
        } else {
            minRange.get(index)[0] = value[0];
            minRange.get(index)[1] = value[1];
            minRange.get(index)[2] = value[2];
        }
        lastIndex = index;
    }
}

Version #1 Stack
Time Worstcase O(n)
SpaceO (n)

class StockSpanner {
    Stack<int[]> stack;

    public StockSpanner() {
        this.stack = new Stack<>();
    }

    public int next(int price) {
        int count = 1;
        while (!stack.isEmpty() && stack.peek()[0] <= price) {
            count += stack.pop()[1];
        }
        stack.push(new int[]{price, count});
        return count;
    }
}