917. Reverse Only Letters

Given a string S, return the “reversed” string where all characters that are not a letter stay in the same place, and all letters reverse their positions.

 

Example 1:

Input:

"ab-cd"

Output:

"dc-ba"

Example 2:

Input:

"a-bC-dEf-ghIj"

Output:

"j-Ih-gfE-dCba"

Example 3:

Input:

"Test1ng-Leet=code-Q!"

Output:

"Qedo1ct-eeLg=ntse-T!"

 

Note:

  1. S.length <= 100
  2. 33 <= S[i].ASCIIcode <= 122
  3. S doesn’t contain \ or "

 

Straightforward solution. 

  1. collect letters in reverse order.
  2. go through string from beginning, if it’s letter, replace with letter from reverse string, else keep special chars and adjust pointer accordingly
  3. of course there’s space for improvement, but not necessary
<?php
class Solution {

    /**
     * @param String $S
     * @return String
     */
    function reverseOnlyLetters($S) {
        $x = '';
        $y = '';
        for($i = strlen($S)-1; $i >=0; $i -- ){
            if(ctype_alpha($S[$i])){
                $x .= $S[$i];
            }
        }
        $xi = 0;
        for($i = 0; $i < strlen($S); $i ++){
            if(!ctype_alpha($S[$i])){
                $y .= $S[$i];
            } else {
                $y .= $x[$xi];
                $xi ++;
            }
             
        }
        
        return $y;
    }
}

?>

 

7. Reverse Integer

Given a 32-bit signed integer, reverse digits of an integer.

Example 1:

Input:

 123

Output:

 321

Example 2:

Input:

 -123

Output:

 -321

Example 3:

Input:

 120

Output:

 21

Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231,  231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

class Solution {

    /**
     * @param Integer $x
     * @return Integer
     */
    function reverse($x) {
        
        $r =  (int) (strrev(trim($x,"+-")) * ($x>0?1:-1));
        
        if($r >  pow(2,31)-1 || $r < -pow(2,31)){
            return 0;
        }
        return $r;
    }
}

 

9. Palindrome Number

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1:

Input:

 121

Output:

 true

Example 2:

Input:

 -121

Output:

 false

Explanation:

 From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.

Example 3:

Input:

 10

Output:

 false

Explanation:

 Reads 01 from right to left. Therefore it is not a palindrome.

Follow up:

Coud you solve it without converting the integer to a string?

 

class Solution {

    /**
     * @param Integer $x
     * @return Boolean
     */
    function isPalindrome($x) {
        if($x < 0){
            return false;
        }
        return strrev($x) == $x;
    }
}

For the followup

not converting to string? Create a  stack of integers instead (like a push down automata)

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

 

26. Remove Duplicates from Sorted Array


Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

Example 1:

Given nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.

It doesn’t matter what you leave beyond the returned length.
Example 2:

Given nums = [0,0,1,1,1,2,2,3,3,4],

Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.

It doesn’t matter what values are set beyond the returned length.
Clarification:

Confused why the returned value is an integer but your answer is an array?

Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.

Internally you can think of this:

// nums is passed in by reference. (i.e., without making a copy)
int len = removeDuplicates(nums);

// any modification to nums in your function would be known by the caller.
// using the length returned by your function, it prints the first len elements.
for (int i = 0; i < len; i++) {
print(nums[i]);
}


class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function removeDuplicates(&$nums) {
        if(empty($nums)){
            return 0;
        }
        $i = 0;
        $r = 1;
        while($i < count($nums)-1){
            if($nums[$i] != $nums[$i+1]){
                $nums[$r] = $nums[$i+1];
                $r ++;
                
            }
            $i ++;
        }
        return $r;
    }
}

 

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