Tag Archives: Leetcode

1032. Stream of Characters

Implement the StreamChecker class as follows:

  • StreamChecker(words): Constructor, init the data structure with the given words.
  • query(letter): returns true if and only if for some k >= 1, the last k characters queried (in order from oldest to newest, including this letter just queried) spell one of the words in the given list.

 

Example:

StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // init the dictionary.
streamChecker.query('a');          // return false
streamChecker.query('b');          // return false
streamChecker.query('c');          // return false
streamChecker.query('d');          // return true, because 'cd' is in the wordlist
streamChecker.query('e');          // return false
streamChecker.query('f');          // return true, because 'f' is in the wordlist
streamChecker.query('g');          // return false
streamChecker.query('h');          // return false
streamChecker.query('i');          // return false
streamChecker.query('j');          // return false
streamChecker.query('k');          // return false
streamChecker.query('l');          // return true, because 'kl' is in the wordlist

 

Note:

  • 1 <= words.length <= 2000
  • 1 <= words[i].length <= 2000
  • Words will only consist of lowercase English letters.
  • Queries will only consist of lowercase English letters.
  • The number of queries is at most 40000.

TLE Version (First Draft)

This is the version I submitted during the contest, TLE. (obviously, for a hard question)

My idea was building a tree, well, I just hate writing another class…. so I tried in a hard way during the contest.

class StreamChecker {
    public $max = 0;
    public $hist = "";
    public $d;

    /**
     * @param String[] $words
     */
    function __construct($words) {
        error_reporting(0);
        ini_set('display_errors', 0);
        $this-> d = $words;
        foreach($words as $w){
           $this ->max = max(strlen($w), $this ->max); 
        }
        
    }
  
    /**
     * @param String $letter
     * @return Boolean
     */
    function query($letter) {

        $this ->hist .= $letter;
        foreach($this->d as $f){
            if ($this -> endsWith($this -> hist,$f)) {
                
                return true;
            }
        } 
        if(strlen($this->hist) > $max){
            $this->hist = substr($this->hist, -($this->max));
        }
        
        return false;
    }
    
    function endsWith($haystack, $needle)
    {
        $length = strlen($needle);
        if ($length == 0) {
            return true;
        }
        return (substr($haystack, -$length) === $needle);
    }
}

/**
 * Your StreamChecker object will be instantiated and called as such:
 * $obj = StreamChecker($words);
 * $ret_1 = $obj->query($letter);
 */

Another Try

for the query part, if the char is not the last char of any word in the dictionary, return false. The method actually passed all the tests, 2000+ms.

It’s actually a single level trie tree..   in the form of an array.

 

class StreamChecker {
    public $max = 0;
    public $hist = "";
    public $first = [];
    public $d;

    /**
     * @param String[] $words
     */
    function __construct($words) {
        error_reporting(0);
        ini_set('display_errors', 0);
        $this-> d = $words;
        foreach($words as $w){
            $this ->max = max(strlen($w), $this ->max); 
            $this -> first[] = $w[strlen($w)-1];
        }
        
    }
  
    /**
     * @param String $letter
     * @return Boolean
     */
    function query($letter) {
        $this ->hist .= $letter;
        if(!in_array($letter,$this->first)){
            return false;
        }
        foreach($this->d as $f){
            if ($this -> endsWith($this -> hist,$f)) {
                
                return true;
            }
        } 
        if(strlen($this->hist) > $max){
            $this->hist = substr($this->hist, -($this->max));
        }
        
        return false;
    }
    
    function endsWith($haystack, $needle)
    {
        $length = strlen($needle);
        if ($length == 0) {
            return true;
        }
        return (substr($haystack, -$length) === $needle);
    }
}

/**
 * Your StreamChecker object will be instantiated and called as such:
 * $obj = StreamChecker($words);
 * $ret_1 = $obj->query($letter);
 */

 

1031. Maximum Sum of Two Non-Overlapping Subarrays

Given an array A of non-negative integers, return the maximum sum of elements in two non-overlapping (contiguous) subarrays, which have lengths L and M.  (For clarification, the L-length subarray could occur before or after the M-length subarray.)

Formally, return the largest V for which V = (A[i] + A[i+1] + ... + A[i+L-1]) + (A[j] + A[j+1] + ... + A[j+M-1]) and either:

  • 0 <= i < i + L - 1 < j < j + M - 1 < A.lengthor
  • 0 <= j < j + M - 1 < i < i + L - 1 < A.length.

 

Example 1:

Input:

A = [0,6,5,2,2,5,1,9,4], L = 1, M = 2

Output:

20
Explanation: One choice of subarrays is [9] with length 1, and [6,5] with length 2.

Example 2:

Input:

A = [3,8,1,3,2,1,8,9,0], L = 3, M = 2

Output:

29
Explanation: One choice of subarrays is [3,8,1] with length 3, and [8,9] with length 2.

Example 3:

Input:

A = [2,1,5,6,0,9,5,0,3,8], L = 4, M = 3

Output:

31
Explanation: One choice of subarrays is [5,6,0,9] with length 4, and [3,8] with length 3.

 

Note:

  1. L >= 1
  2. M >= 1
  3. L + M <= A.length <= 1000
  4. 0 <= A[i] <= 1000
class Solution {

    /**
     * @param Integer[] $A
     * @param Integer $L
     * @param Integer $M
     * @return Integer
     */
    function maxSumTwoNoOverlap($A, $L, $M) {
        $max  = 0;
        $a = [];
        $b = [];
        for($i  = 0; $i < count($A)-$L+1; $i ++){
            $a[$i] =  array_sum(array_slice($A,$i,$L));
        }
        
        for($j = 0; $j < count($A)-$M+1; $j ++){
            $b[$j] = array_sum(array_slice($A,$j,$M));
        }
        arsort($a);arsort($b);
        foreach($a as $ak => $av){
            foreach($b as $bk => $bv){
                if($bk + $M <= $ak || $ak + $L <= $bk){
                    $max = max($max, $av + $bv);

                }
            }
        }
        
        return $max;
    }
}

160ms

Thoughts:

  • My code is the version used for contest, so..
  • The length of inputs (1000) seems relatively small, so just follow your heart, again…
  • Idea, scan & store sums for L &  M fixed size arrays.
  • for each sum L and for each sum M, if no overlap, the check and update max total.
  • What makes it slow:
    • array_sum.. fixed size sliding door works better, but more codes…
    • double for each, there’s an obvious pattern to move index out of overlap.
  • Having these sorts have 10ms improvement, which is quite interesting.

Improved Version

class Solution {

    /**
     * @param Integer[] $A
     * @param Integer $L
     * @param Integer $M
     * @return Integer
     */
    function maxSumTwoNoOverlap($A, $L, $M) {
        $max  = 0;
        $a = [];
        $b = [];

        for($i  = 0; $i < count($A)-$L+1; $i ++){
            if($i == 0){
                $a[$i] =  array_sum(array_slice($A,$i,$L));
            } else {
                $a[$i] = $a[$i-1] - $A[$i-1] + $A[$i+$L-1];
            }
        }
        
        for($i = 0; $i < count($A)-$M+1; $i ++){
            if($i == 0){
                $b[$i] =  array_sum(array_slice($A,$i,$M));
            } else {
                $b[$i] = $b[$i-1] - $A[$i-1] + $A[$i+$M-1];
            }
        }
        for($i = 0; $i < count($a); $i++){
            for($j = 0; $j < count($b);$j++){
                if($j + $M <= $i || $i + $L <= $j){
                    $max = max($max, $a[$i] + $b[$j]);
                } else if($j + $M <= $i){
                    $j += ($M-1);
                }
            }
        }
        
        return $max;
    }
}
  • The “fixed size sliding door” saved about 20ms
  • No significant improvement for the double for each.

1030. Matrix Cells in Distance Order

We are given a matrix with R rows and C columns has cells with integer coordinates (r, c), where 0 <= r < R and 0 <= c < C.

Additionally, we are given a cell in that matrix with coordinates (r0, c0).

Return the coordinates of all cells in the matrix, sorted by their distance from (r0, c0) from smallest distance to largest distance.  Here, the distance between two cells (r1, c1) and (r2, c2) is the Manhattan distance, |r1 - r2| + |c1 - c2|.  (You may return the answer in any order that satisfies this condition.)

 

Example 1:

Input:

R = 1, C = 2, r0 = 0, c0 = 0

Output:

[[0,0],[0,1]]
Explanation: The distances from (r0, c0) to other cells are: [0,1]

Example 2:

Input:

R = 2, C = 2, r0 = 0, c0 = 1

Output:

[[0,1],[0,0],[1,1],[1,0]]
Explanation: The distances from (r0, c0) to other cells are: [0,1,1,2]
The answer [[0,1],[1,1],[0,0],[1,0]] would also be accepted as correct.

Example 3:

Input:

R = 2, C = 3, r0 = 1, c0 = 2

Output:

[[1,2],[0,2],[1,1],[0,1],[1,0],[0,0]]
Explanation: The distances from (r0, c0) to other cells are: [0,1,1,2,2,3]
There are other answers that would also be accepted as correct, such as [[1,2],[1,1],[0,2],[1,0],[0,1],[0,0]].

 

Note:

  1. 1 <= R <= 100
  2. 1 <= C <= 100
  3. 0 <= r0 < R
  4. 0 <= c0 < C
class Solution {

    /**
     * @param Integer $R
     * @param Integer $C
     * @param Integer $r0
     * @param Integer $c0
     * @return Integer[][]
     */
    function allCellsDistOrder($R, $C, $r0, $c0) {

        $a =[];

        for($x = 0; $x < $R; $x ++){
           for($y = 0; $y < $C; $y ++){
             $a[] = [$x,$y];
           } 
        }
        usort($a, function($arr1, $arr2) use ($r0,$c0) {
            return (abs($arr1[0]-$r0)+ abs($arr1[1]-$c0) 
                    > 
                    abs($arr2[0]-$r0)+ abs($arr2[1]-$c0)
                   ) ? 1 : -1;
        });
        
        return $a;
        
    }
    

}

Thoughts:

  • For all easy level leetcode, just follow you heart, no need for advanced algorithms.
  • My solution:
    • Array Fill
    • Sort by  Manhattan distance
    • return

1029. Two City Scheduling

There are 2N people a company is planning to interview. The cost of flying the i-th person to city A is costs[i][0], and the cost of flying the i-th person to city B is costs[i][1].

Return the minimum cost to fly every person to a city such that exactly Npeople arrive in each city.

 

Example 1:

Input:

[[10,20],[30,200],[400,50],[30,20]]

Output:

110

Explanation:

The first person goes to city A for a cost of 10.
The second person goes to city A for a cost of 30.
The third person goes to city B for a cost of 50.
The fourth person goes to city B for a cost of 20.

The total minimum cost is 10 + 30 + 50 + 20 = 110 to have half the people interviewing in each city.

 

Note:

  1. 1 <= costs.length <= 100
  2. It is guaranteed that costs.length is even.
  3. 1 <= costs[i][0], costs[i][1] <= 1000

 

class Solution {

    /**
     * @param Integer[][] $costs
     * @return Integer
     */
    function twoCitySchedCost($costs) {
        usort($costs, function($arr1, $arr2) {
            return (abs($arr1[1]-$arr1[0]) < abs($arr2[1]-$arr2[0]) ) ? 1 : -1;
        });

        $a = 0;
        $b = 0;
        $total = 0;
        foreach($costs as $c){
            if($c[0] < $c[1]){

                if($a < count($costs)/2){
                    $total += $c[0];
                    $a ++;
                } else {
                    $total += $c[1];
                    $b ++;
                }
               
            } else{
                if($b < count($costs)/2){
                    $total += $c[1];
                    $b ++;
                } else {
                    $total += $c[0];
                    $a ++;
                }
                
            } 
        } 

        return $total;
    }
}

16ms.

 

 

Thoughts:

  • This code was used for the contest, so it’s not well structured (in terms of redundancy)
  • The basic idea:
    • Sort by switching cost (price diff), DESC.
    • then for each person, assign to lower cost city until full.
      • in case of full, assign to city with higher cost
    • Since sorted by price diff, at the time one city is full,  the cost to switch remaining people to the second choice is the lowest

If I’m a interviewer:

  • Let’s try three cities….
  • What about the capacity of each city is specified?
  • And what about the capacity is flexible and within a range provided?

1021. Remove Outermost Parentheses

A valid parentheses string is either empty ("")"(" + A + ")", or A + B, where A and B are valid parentheses strings, and + represents string concatenation.  For example, """()""(())()", and "(()(()))" are all valid parentheses strings.

A valid parentheses string S is primitive if it is nonempty, and there does not exist a way to split it into S = A+B, with A and B nonempty valid parentheses strings.

Given a valid parentheses string S, consider its primitive decomposition: S = P_1 + P_2 + ... + P_k, where P_i are primitive valid parentheses strings.

Return S after removing the outermost parentheses of every primitive string in the primitive decomposition of S.

 

Example 1:

Input:

"(()())(())"

Output:

"()()()"

Explanation:

The input string is "(()())(())", with primitive decomposition "(()())" + "(())".
After removing outer parentheses of each part, this is "()()" + "()" = "()()()".

Example 2:

Input:

"(()())(())(()(()))"

Output:

"()()()()(())"

Explanation:

The input string is "(()())(())(()(()))", with primitive decomposition "(()())" + "(())" + "(()(()))".
After removing outer parentheses of each part, this is "()()" + "()" + "()(())" = "()()()()(())".

Example 3:

Input:

"()()"

Output:

""

Explanation:

The input string is "()()", with primitive decomposition "()" + "()".
After removing outer parentheses of each part, this is "" + "" = "".

 

Note:

  1. S.length <= 10000
  2. S[i] is "(" or ")"
  3. S is a valid parentheses string

class Solution {
    public String removeOuterParentheses(String S) {
        int lv = 0;
        String result = "";
        
        for(char c : S.toCharArray()){
            if(c == '('){
                if(lv > 0){
                    result += c;
                }
                lv ++;
                
            } else if(c == ')'){
                lv--;
                if(lv > 0){
                    result += c;
                }
            }
        }
        return result;
    }
}

 

* Using a StringBuilder will somehow improve the performance.

Thoughts:

Since we can assume the input is valid, just use a counter to mark the depth. Send char to result only when depth >= 1

If I’m a Interviewer

  1. What if the input string is not always valid?
    • ref: LC20
  2. What if we upgrade parentheses to brackets ()[]{} ?
    • Use Stack and Stack.size() instead of level counter
  3. What if we remove inner most (max depth) parentheses instead?
    • Go through twice, 1) find max depth, 2) copy to result and skip max depth.

Well we can always construct an array of ints (levels) as a form of representation.

For example, “(()())(())(()(()))” -> [1,2,2,1,2,1,2,2,3]

Then we can easily remove any levels (outer/inner/somewhere in the middle).

  • Remove Outer: remove 1, everything else —
  • Remove Inner: remove max
  • Remove Level2: remove 2, everything > 2 decrease by 1.

 


23. Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

Example:

Input:

[
  1->4->5,
  1->3->4,
  2->6
]

Output:

 1->1->2->3->4->4->5->6


Thoughts:

This is my accepted but not really efficient solution. (in the last 10% in CPU time and Mem Usage)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode cur = new ListNode(0);
        ListNode result = cur;
        while(!isAllEmpty(lists)){

            int min = Integer.MAX_VALUE;
            int min_index = Integer.MAX_VALUE;
            int i = -1;
            for(ListNode l : lists){
                i ++;
                if (l == null){
                    continue;
                }
                if(l.val < min){
                    min = l.val;
                    min_index = i;
                }
                
            }
           
            cur.next = lists[min_index];
            cur = cur.next;
            lists[min_index] = lists[min_index].next;
        }
        
        return result.next;
    }
    
    
    public boolean isAllEmpty(ListNode[] ln){
        for(ListNode l : ln){
            if(l != null){
                return false;
            }
        }
        return true;
    }
}

 

 


451. Sort Characters By Frequency

Given a string, sort it in decreasing order based on the frequency of characters.

Example 1:

Input:
"tree"

Output:
"eert"

Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.

Example 2:

Input:
"cccaaa"

Output:
"cccaaa"

Explanation:
Both 'c' and 'a' appear three times, so "aaaccc" is also a valid answer.
Note that "cacaca" is incorrect, as the same characters must be together.

Example 3:

Input:
"Aabb"

Output:
"bbAa"

Explanation:
"bbaA" is also a valid answer, but "Aabb" is incorrect.
Note that 'A' and 'a' are treated as two different characters.

class Solution {

    /**
     * @param String $s
     * @return String
     */
    function frequencySort($s) {
        $c = [];
        for($i = 0 ; $i < strlen($s); $i++){
            $char = $s[$i];
            $c[$char] ++;
        }
        
        arsort($c);
        $result = "";
        foreach($c as $k => $v){
            while($v > 0){
                $result .= $k;
                $v --;
            }
        }
        return $result;
    }
}

well, PHP is actually pretty good at this.

Doing same thing in Java is quite annoying (typing speed matters)

22. Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

class Solution {

    /**
     * @param Integer $n
     * @return String[]
     */
    function generateParenthesis($n) {
        $result = [];
        $this->helper(0, 0, $n, "", $result);
        return $result;
    }
    
    function helper($l, $r, $max, $str, &$result){
        if($l + $r == $max*2){
            $result[] = $str;
            return;
        }
        if($l < $max){
            $this->helper($l+1, $r, $max, $str."(", $result);
        }
        
        if($r < $l){
            $this->helper($l, $r+1, $max, $str.")", $result);
        }
    }
}