406. Queue Reconstruction by Height

Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue.

Note:
The number of people is less than 1,100.

Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

 

Example

Solution:

<?php

class Solution {

    /**
     * @param Integer[][] $people
     * @return Integer[][]
     */
    function reconstructQueue($people) {
        usort($people, function($p1, $p2){
            return ($p1[0] !== $p2[0])?
                 $p2[0] <=> $p1[0] : $p1[1] <=> $p2[1];
        });
        $result = [];
        foreach($people as $p){
            array_splice($result, $p[1], 0, [$p]);
        }

        return $result;
    }
}

?>

 

[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

The higher the person is, the more importance it has for other persons

  • So starting sort by height, DESC
  • Then for each height level, sort by # of higher heads in the front, ASC
  • (Just like ‘ORDER BY h DESC, k ASC’ in SQL)

Now we have:

More Important to Others <===> Less Important to Others

[7,0]    [7,1]     [6,1]    [5,0]    [5,2]   [4,4]

Then set group height = 7 to the result

[7,0] [7,1]  ;   TBD: [6,1]    [5,0]    [5,2]   [4,4]

Now set group  height = 6. It could be places any where, since h=7 can’t see them, so the position is determined by their value of k. for example: [6,1]. there’s one higher/equal height person ahead, we can simply insert it right after k is matched, and push everyone else backwards safely since they don’t care about lower person moving around.

   0     1     2     3     4  ..... (index)

[7,0] [6, 1] [7,1]  ;                TBD:    [5,0]    [5,2]   [4,4]

[5,0] [7,0] [6, 1] [7,1]  ;          TBD:    [5,2]   [4,4]

[5,0] [7,0] [5,2] [6, 1] [7,1]  ;    TBD:    [4,4]

[5,0] [7,0] [5,2] [6, 1] [4,4]  [7,1]

 

 

In PHP, array_splice($result, $p[1], 0, [$p]);  means insert p to position p[i] and move people behind backwards

In Java, LinkedList seems easier.

In Python, there’s even easier method (list.insert(index, value))

911. Online Election

In an election, the i-th vote was cast for persons[i] at time times[i].

Now, we would like to implement the following query function: TopVotedCandidate.q(int t) will return the number of the person that was leading the election at time t.

Votes cast at time t will count towards our query.  In the case of a tie, the most recent vote (among tied candidates) wins.

 

Example 1:

Input:

["TopVotedCandidate","q","q","q","q","q","q"], [[[0,1,1,0,0,1,0],[0,5,10,15,20,25,30]],[3],[12],[25],[15],[24],[8]]

Output:

[null,0,1,1,0,0,1]

Explanation:

At time 3, the votes are [0], and 0 is leading.
At time 12, the votes are [0,1,1], and 1 is leading.
At time 25, the votes are [0,1,1,0,0,1], and 1 is leading (as ties go to the most recent vote.)
This continues for 3 more queries at time 15, 24, and 8.

 

Note:

  1. 1 <= persons.length = times.length <= 5000
  2. 0 <= persons[i] <= persons.length
  3. times is a strictly increasing array with all elements in [0, 10^9].
  4. TopVotedCandidate.q is called at most 10000 times per test case.
  5. TopVotedCandidate.q(int t) is always called with t >= times[0].

 

Here’s my rejected solution

<?php
class TopVotedCandidate {
    
    public $dic=[];
    public $r =[];

    public $keys = [];
    /**
     * @param Integer[] $persons
     * @param Integer[] $times
     */
    function __construct($persons, $times) {
        $max = 0;
        $prev_person = null;
        for($i = 0; $i < count($times); $i ++){
            $this->inc($persons[$i]);
            arsort($this->$dic);
  
            foreach($this->$dic as $k=>$v){
                $max_this_round = $k;
                break;
            }
            $person_this_round = $persons[$i];

            if($i > 0){
                if($max_this_round === $max){
                    $person_this_round = $prev_person;
                } 
            }
            echo $person_this_round;
            $this->$r[$times[$i]] = $person_this_round;
            $max = $max_this_round;
            $prev_person = $persons[$i];
        }
        var_dump($this->$r);
        ksort($this->$r);
        var_dump($this->$r);
        $this->$keys = array_keys($this->$r);
        
    }
  
    /**
     * @param Integer $t
     * @return Integer
     */
    function q($t) {
        $k =  $this->binarySearch($t);
        return $this->$r[$k];
    }
    
    function inc($p){
        if(isset($this->$dic[$p])){
            $this->$dic[$p] ++;
        } else {
            $this->$dic[$p] = 1;
        }
    }
    
    
    function binarySearch($x) { 
        $arr =  $this->$keys;
        $low = 0; 
        $high = count($arr) - 1; 
        

        while ($low <= $high) { 

            // compute middle index 
            $mid = floor(($low + $high) / 2); 

            // element found at mid 
            if($arr[$low] <= $x && $arr[$mid] >= $x &&  $mid - $low <= 1) { 
                return $low; 
            } 

            if ($x < $arr[$mid]) { 
                // search the left side of the array 
                $high = $mid -1; 
            } 
            else { 
                // search the right side of the array 
                $low = $mid + 1; 
            } 
            echo "$low-$mid-$high\n";
        } 

        return false; 
    }
}

/**
 * Your TopVotedCandidate object will be instantiated and called as such:
 * $obj = TopVotedCandidate($persons, $times);
 * $ret_1 = $obj->q($t);
 */

?>

Here are the problems:

  • Just like the previous problem, my PHP syntax is wrong,  and the prev problem is accepted.  I didn’t even ever question about the syntax
  • And I wasted too much time on debugging, caused by syntax.
  • And my modified binary search isn’t working
  • And yes, that’s totally a mess

Here’s the my accepted solution

<?php
class TopVotedCandidate {
    
    public $dic=[];
    public $r =[];

    public $keys = [];
    /**
     * @param Integer[] $persons
     * @param Integer[] $times
     */
    function __construct($persons, $times) {
        $prev_max = 0;
        $prev_winner = null;

        for($i = 0; $i < count($times); $i ++){
            $this->inc($persons[$i]);

            arsort($this->dic);

            reset($this->dic);
            $winner = key($this->dic);
            
            $max = $this->dic[$winner];
            if($prev_winner !== null){
                if($max == $prev_max){
                    $winner = $prev_winner;
                }
            }
            if($this->dic[$persons[$i]] == $this->dic[$winner]){
                 $winner = $persons[$i];
            }

            $prev_max = max($prev_max, $max);
            $prev_winner = $winner;
            $this->r[$times[$i]] = $winner;
            
        }
        ksort($this->r);
        $this->keys = array_keys($this->r);
        
    }
  
    /**
     * @param Integer $t
     * @return Integer
     */
    function q($t) {
        $k =  $this->binarySearch($t);
        echo "$t => $k";
        return $this->r[$k];
    }
    
    function inc($p){
        if(isset($this->dic[$p])){
            $this->dic[$p] ++;
        } else {
            $this->dic[$p] = 1;
        }
    }
    
    // This is a modified binary search, finding the nearest smaller index 
    // just like floorKey in Java's TreeMap
    function binarySearch($x) { 
        $arr =  $this->keys;
        $low = 0; 
        $high = count($arr) - 1; 
        
        
        if($x < $arr[$low]){
            return false;
        }
        
        while ($high >= $low) { 
            $mid = $low + floor(($high - $low) / 2); 

            if($x >= $arr[$high]){
                return (int) $arr[$high];
            }
            
            if($arr[$mid] == $x) { 
                return (int) $arr[$mid]; 
            } 

            if ($x < $arr[$mid]) { 
                $high = $mid-1; 
            } else { 
                $low = $mid+1; 
            } 
            
        } 
        return (int) $arr[$low-1];

    }
}
?>
/**
 * Your TopVotedCandidate object will be instantiated and called as such:
 * $obj = TopVotedCandidate($persons, $times);
 * $ret_1 = $obj->q($t);
 */

 

 

1094. Car Pooling

You are driving a vehicle that has capacity empty seats initially available for passengers.  The vehicle only drives east (ie. it cannot turn around and drive west.)

Given a list of tripstrip[i] = [num_passengers, start_location, end_location] contains information about the i-th trip: the number of passengers that must be picked up, and the locations to pick them up and drop them off.  The locations are given as the number of kilometers due east from your vehicle’s initial location.

Return true if and only if it is possible to pick up and drop off all passengers for all the given trips.

 

Example 1:

Input:

trips = [[2,1,5],[3,3,7]], capacity = 4

Output:

false

Example 2:

Input:

trips = [[2,1,5],[3,3,7]], capacity = 5

Output:

true

Example 3:

Input:

trips = [[2,1,5],[3,5,7]], capacity = 3

Output:

true

Example 4:

Input:

trips = [[3,2,7],[3,7,9],[8,3,9]], capacity = 11

Output:

true

 

Accepted  Solution in wrong PHP syntax (don’t drink and code)

<?php
class Solution {

     public $dic=[];
    /**
     * @param Integer[][] $trips
     * @param Integer $capacity
     * @return Boolean
     */
    function carPooling($trips, $capacity) {
        $max = 0;
        $sum = 0;
        $this->$dic = [];
        foreach ($trips as $c){
            if(!isset($this->$dic[$c[1]])){
                $this->$dic[$c[1]] = 0;
            }
            $this->$dic[$c[1]] += $c[0];
            $this->$dic[$c[2]] -= $c[0];
        }
        // 
        ksort($this->$dic);
    
        // Calculate least expected capacity
        foreach($this->$dic as $d){
            $sum += $d;
            if($sum > $max){
                $max  = $sum;
            }
        }
   
        return $max <= $capacity;
    }
}
?>

And Here’s the solution in my mind..

<?php
class Solution {

     public $dic=[];
    /**
     * @param Integer[][] $trips
     * @param Integer $capacity
     * @return Boolean
     */
    function carPooling($trips, $capacity) {
        $max = 0;
        $sum = 0;
        $this->dic = [];
        foreach ($trips as $c){
            if(!isset($this->dic[$c[1]])){
                $this->dic[$c[1]] = 0;
            }
            $this->dic[$c[1]] += $c[0];
            $this->dic[$c[2]] -= $c[0];
        }

        ksort($this->dic);
    
        // I'm finding the min capacity here, but it's not necessary 
        foreach($this->dic as $d){
            $sum += $d;
            if($sum > $max){
                $max  = $sum;
            }
        }
   
        return $max <= $capacity;
    }   
}

?>

 

1100. Find K-Length Substrings With No Repeated Characters

Given a string S, return the number of substrings of length K with no repeated characters.

 

Example 1:

Input:

S = "havefunonleetcode", K = 5

Output:

6

Explanation:

There are 6 substrings they are : 'havef','avefu','vefun','efuno','etcod','tcode'.

Example 2:

Input:

S = "home", K = 5

Output:

0

Explanation:

Notice K can be larger than the length of S. In this case is not possible to find any substring.

 

Note:

  1. 1 <= S.length <= 10^4
  2. All characters of S are lowercase English letters.
  3. 1 <= K <= 10^4

 

Quite straight forward solution.

the brute force way is foreach K chars, check dupes.

to optimize that, push next char and remove last instead, so same work won’t be done multiple times

<?php
class Solution {

    /**
     * @param String $S
     * @param Integer $K
     * @return Integer
     */
    function numKLenSubstrNoRepeats($S, $K) {
        if($K > strlen($S)){
            return 0;
        }
        // This is not necessary in PHP
        $arr = str_split($S);
        $dic = [];
        $result = 0;
        
        // Helper, any repeated chars so far?
        $unique = static function() use (&$dic) {
            foreach($dic as $v){
                if ($v > 1){
                    return false;
                }
            }
            return true;
        };

        // Load first K chars
        for($i = 0; $i < $K; $i ++){
            if(isset($dic[$arr[$i]])){
                $dic[$arr[$i]]++;
            } else {
                $dic[$arr[$i]] = 1;
            }
            
        }
        // First K has repeat? update counter
        if($unique()){
             $result++;
        }

        // Starting from K, take next char and remove the last one, update dictionary, and check after each round
        for($in = $K; $in < strlen($S); $in ++){
            if(isset($dic[$arr[$in]])){
                $dic[$arr[$in]]++;
            } else {
                $dic[$arr[$in]] = 1;
            }
            
            $out = $in-$K;
            $dic[$arr[$out]]--;
            
            if($unique()){
                $result++;
            }
        }
            
        return $result;
    }
}
?>

 

24. Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list’s nodes, only nodes itself may be changed.

 

Example:

Given 1->2->3->4, you should return the list as 2->1->4->3.

/**
 * Definition for a singly-linked list.
 * class ListNode {
 *     public $val = 0;
 *     public $next = null;
 *     function __construct($val) { $this->val = $val; }
 * }
 */
class Solution {

    /**
     * @param ListNode $head
     * @return ListNode
     */
    function swapPairs($head) {
        if($head === null || $head->next === null){
            return $head;
        }
        
        $r = $head->next;
        $temp = $r->next;
        $r->next = $head;
        $r->next ->next = $this->swapPairs($temp);
        return $r;
    }
}

 

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.

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);
        }
    }
}