It has almost been a year since I wrote my first leetcode blog post. Today LeetCode starts the 30-Day LeetCoding Challenge. Recently, I am learning golang, and I think praticing LeetCode is a good way to learn a new language, so I will use golang to solve these 30 LeetCode problems.
Week 1: April 1st–April 7th
Single Number
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example 1:
1 |
|
Example 2:
1 |
|
Explanation
- We can use
XOR
to solve this problem. We know that0 XOR 0 = 0
,1 XOR 1 = 0
,0 XOR 1 = 1 XOR 0 = 1
. For example, we can initialize the res is0000
first, loop through all the numbers, if the first number is1010
thenres XOR num = 0000 XOR 1010 = 1010
. If the second number is also1010
, thenres = res XOR num = 1010 XOR 1010 = 0000
; If the third number is1100
, then theres = res XOR num = 0000 XOR 1100 = 1100
. So we return the third number.
From: [LeetCode] 136. Single Number
Solution
1 |
|
Happy Number
Write an algorithm to determine if a number is “happy”.
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
Example:
1 |
|
Explanation
- We can also use two pointer technique to solve this problem. Similar to 141. Linked List Cycle. The difference is in this problem, the cycle must exist.
slow
will be the sum of the digit square, in other words,slow=calc(slow)
,fast
will befast=calc(cal(fast))
. Whenslow
is equals tofast
, we break out the loop, and check ifslow
is equals to 1. If it’s 1, we return true; else return false.
Solution
1 |
|
Maximum Subarray
Given an integer array nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
1 |
|
Follow up:
1 |
|
Explanation 1
-
We are finding the maximum of a subarray, which means we need to continuosily adding numbers, also we need to return one maximum number, which means we need to have a variable to keep track of the maximum.
-
While iterating, the sum is keep adding current number. If the sum is less than the current number, we can just drop the sum, and reset the sum to the current number. And we compare the sum with the maximum result.
-
Finally, return the maximum result.
From: [LeetCode] 53. Maximum Subarray
Solution 1
1 |
|
Explanation 2
- We can also use divide and conquer method to solve this problem. First, we divide the array into left half and right half, and find their max sum. We also need to find the max sum for the middle part which is crossing the left half and right half, and we can find it by starting from the middle number and scan left side and scan the right side. Finally, compare these three sums.
From: [LeetCode] 53. Maximum Subarray
Solution 2
1 |
|
Move Zeroes
Given an array nums
, write a function to move all 0
’s to the end of it while maintaining the relative order of the non-zero elements.
Example:
1 |
|
Note:
-
You must do this in-place without making a copy of the array.
-
Minimize the total number of operations.
Explanation
- We can use two pointers
nonZeroIdx
is initalized pointing to the first index, and it is using to points to the first non zero value.i
is increasing moving forward. Ifnums[i]
is not zero, then we swapnums[nonZeroIdx]
andnums[i]
and movenonZeroIdx
one step forward. So that next iteration, ifnums[i]
is not zero again, it will be swapped in front; else ifnums[i]
is zero, it stays the same position.
Solution
1 |
|
Best Time to Buy and Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).
Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Explanation
-
Check if the array is empty, if it is, then return 0;
-
Loop through the array, compare current element with its next element.
- If the next element is greater, then we do noting, just wait for the next element to subtract the minimum element, if reach the end and the next element is still greater, then we sell the minimum using the next element and return the result.
- If the next element is smaller, then we know we need to sell our stock with the current price, and then update the minimum to the next element.
1
2
3[1, 3, 5, 7, 9, 2] => 9 - 1 = 8 min is the first element 1, we wait for the 9 to subtract it, and update the min to 2.
From: [LeetCode] 122. Best Time to Buy and Sell Stock II
Solution
1 |
|
Group Anagrams
Given an array of strings, group anagrams together.
Example:
1 |
|
Note:
-
All inputs will be in lowercase.
-
The order of your output does not matter.
Explanation 1
-
We want to put all same anagrams into a list, so we can sort all strings, then if two sorted strings are equal, then they have the same anagram.
-
Iterating each string, we can get the string then make it as a char array then do sorting. We put the sorted string into a
hashmap<String, List<String>>
as key, and the original string as value. -
After finish iteration, we can retun the hashmap’s values as a new array list as the result.
From: [LeetCode] 49. Group Anagrams
Solution 1
1 |
|
Explanation 2
- Instead of sorting each string, for each string, we know that if two strings are anagrams, then they will have the same 26 lower case characters frequency. Since the input strings are all lower case, we make an array of size 26 and it’s used to store the frequency of each string. After we storing the frequency to the array, we loop through this frequency array and concat each frequency to a string builder so that we can use it as the key of the hashmap.
Solution 2
1 |
|
Counting Elements
Given an integer array arr
, count element x
such that x + 1
is also in arr
.
If there’re duplicates in arr
, count them seperately.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Example 4:
1 |
|
Constraints:
-
1 <= arr.length <= 1000
-
0 <= arr[i] <= 1000
Explanation
New Problem! Below are the hints:
-
Use hashset to store all elements.
-
Loop again to count all valid elements.
Solution
1 |
|
Week 2: April 8th–April 14th
Middle of the Linked List
Given a non-empty, singly linked list with head node head
, return a middle node of linked list.
If there are two middle nodes, return the second middle node.
Example 1:
1 |
|
Example 2:
1 |
|
Note:
- The number of nodes in the given list will be between
1
and100
.
Explanation
-
We can use slow and fast pointers method to solve this problem.
-
Fast and slow pointrs are initialized to
head
. While current fast node and fast.next node is not null, we move fast pointer two steps forward, slow pointer one step forward. Outside the while loop, the slow pointer is the middle node.
Solution
1 |
|
Backspace String Compare
Given two strings S
and T
, return if they are equal when both are typed into empty text editors. #
means a backspace character.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Example 4:
1 |
|
Note:
-
1 <= S.length <= 200
-
1 <= T.length <= 200
-
S
andT
only contain lowercase letters and'#'
characters.
Follow up:
- Can you solve it in
O(N)
time andO(1)
space?
Explanation 1
- We can solve this problem using stack. For each character, if it’s letter, then we push, else if it’s
#
, then we pop. At the end, we compare the size of two stacks.
Solution 1
1 |
|
Explanation 2
-
We can also solve this problem without stack. We think of it comparing character from right to left. First, we define compare indexes
sIdx
andtIdx
to point to the last character ofS
andT
. WhilesIdx
ortIdx
equal or greater than 0, then we pass the string and its compare index to thehelper
function that will returns index of the rightmost symbol in the strings[:i+1]
that’s not deleted by succeeding backspaces. For example if string isabc##
and compare index points at the last character, then the updated compare index will be0
. After running thehelper
function, we compareS[sIdx]
withT[tIdx]
. Then we decrease bothsIdx
andtIdx
to point to the next preceeding character. Outside the while loop, we return if bothsIdx
andtIdx
are negative. -
In the
helper
function, first we define a variableskip
to count how many characters we can remove. While compare index equal or greater than 0, and its pointing character is#
orskip > 0
, then inside the while loop, if current character is#
, we increaseskip
, else decreaseskip
. Next, we decrease the compare index to point to the new left character. Outside the while loop, the compare index will be the updated compare index.
Solution 2
1 |
|
Min Stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
-
push(x) – Push element x onto stack.
-
pop() – Removes the element on top of the stack.
-
top() – Get the top element.
-
getMin() – Retrieve the minimum element in the stack.
Example:
1 |
|
Explanation
-
We can also use only stack to solve this problem, but now, we also need a variable or pointer called
min
that equals to the minimum element. Initialilly,min
set to the largest integer. -
When we push an element, we compare
min
and the element that get pushx
. Ifx
is smaller or equal tomin
, then we first push themin
then update themin
, then pushx
. We first push themin
because thatmin
represents the previousmin
. When we later pop element, we don’t want themin
goes entirely away, we wantmin
to update to the previousmin
. Else if the element we are pushing is greater thanmin
, then we just normally pushx
to the stack.
From: [LeetCode] 155. Min Stack
Solution
1 |
|
Diameter of Binary Tree
Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.
Example:
Given a binary tree
1 |
|
Return 3
, which is the length of the path [4,2,1,3] or [5,2,1,3].
Note: The length of path between two nodes is represented by the number of edges between them.
Explanation 1
-
From the above example, the length
[4,2,1,3]
and[5,2,1,3]
both go through the root node. Their totoal length is equals to the left depth[4, 2, 1]
plus the right depth[1, 3]
. So we can calculate theroot
’s left depth and right depth, then sum them up. This is one situation of having the longest length. The longest length also can be just go through the root’s left child or just the root’s right child. So we need to compare these 3 cases and return the maximum. -
We can also use a HashMap to store the current node and its maximum length. So the key is the TreeNode, the value is its maximum length.
Solution 1
1 |
|
Explanation 2
-
We can also calculate the diameter inside the
getHeight
function. In thegetHeight
function, if the root node is null, then we return 0. Then, we recursively calculate the left height and right height. Next, we can calculate the diameter bymax(res, leftHeight+rightHeight)
. Next, we return the height of the root normally. -
We can also use a
map[TreeNode]int
to memorize the height.
Solution 2
1 |
|
Last Stone Weight
We have a collection of stones, each stone has a positive integer weight.
Each turn, we choose the two heaviest stones and smash them together. Suppose the stones have weights x
and y
with x <= y
. The result of this smash is:
-
If
x == y
, both stones are totally destroyed; -
If
x != y
, the stone of weightx
is totally destroyed, and the stone of weighty
has new weighty-x
.
At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.)
Example 1:
1 |
|
Note:
-
1 <= stones.length <= 30
-
1 <= stones[i] <= 1000
Explanation
- We can use max heap to solve this problem. First, iterate the input array and add each number into the max heap. While the size of the max heap is equal or greater than 2, then we pop two elements out which is the largest two elements. Then calculate the
diff
and push thediff
back to the max heap. Outside the while loop, we check if the heap has size 1 or 0. If the heap has size 1, we return that element, else return 0.
Solution
1 |
|
Contiguous Array
Given a binary array, find the maximum length of a contiguous subarray with equal number of 0 and 1.
Example 1:
1 |
|
Example 2:
1 |
|
Note: The length of the given binary array will not exceed 50,000.
Explanation
-
When we have any subarray problems, we can think of finding subarray’s accumulate sum to solve the problem. In this problem, if the current element is 0, we subtract 1; if the current element is 1, we plus 1. So if any subarray’s sum is 0, then this subarray will have equal number of 0 and 1.
-
We will use a hash map to record the key is the sum, the value is the current index. If next time we have the same sum, then we know in between the subarray sum to 0, and this subarray’s length will be the current index
i
subtracthm.get(sum)
. -
Initially, we will put the entry
{0, -1}
into the hashmap. For example, if the input array is[0, 1]
. When we iterate to number 0, we have sum equals to -1, and we put entry{-1, 0}
into the hashmap. Then when we iterate to number 1, we have sum equals to 0. We check the hashmap has key 0, so we get the length by using current index subtracthm.get(0)
and we get 1 - (-1) = 2.
Solution
1 |
|
Perform String Shifts
You are given a string s
containing lowercase English letters, and a matrix shift
, where shift[i] = [direction, amount]
:
-
direction
can be0
(for left shift) or1
(for right shift). -
amount
is the amount by which strings
is to be shifted. -
A left shift by 1 means remove the first character of
s
and append it to the end. -
Similarly, a right shift by 1 means remove the last character of
s
and add it to the beginning.
Return the final string after all operations.
Example 1:
1 |
|
Example 2:
1 |
|
Constraints:
-
1 <= s.length <= 100
-
s
only contains lower case English letters. -
1 <= shift.length <= 100
-
shift[i].length == 2
-
0 <= shift[i][0] <= 1
-
0 <= shift[i][1] <= 100
Explanation
-
Second new problem! For example, if the string is
abc
. If left shift 1 time, then we havebca
. In other words,s.substring(1) + s.substring(0, 1)
. If right shift 1 time, then we havecba
. In other words,s.substring(3-1) + s.substring(0, 3-1)
. -
First, we need to loop through the
shift
array. We create a variablestart
to count the difference of left shift and right shift. If left shift, then we subtractshift[i][1]
, else we plusshift[i][1]
. -
If
start
is 0, that means the string is return back to the same position, so we returns
. -
To avoid out of bound, we module
start
with the string length. Ifstart
is less than 0, that means we left shift the string byabs(start)
times. Else ifstart
is greater than 0, that means we right shiftstart
times. Using the above explanation’s example, we can easily return the result.
Solution
1 |
|
Week 3: April 15th–April 21st
Product of Array Except Self
Given an array nums
of n integers where n > 1, return an array output
such that output[i]
is equal to the product of all the elements of nums
except nums[i]
.
Example:
1 |
|
Constraint: It’s guaranteed that the product of the elements of any prefix or suffix of the array (including the whole array) fits in a 32 bit integer.
Note: Please solve it without division and in O(n).
Follow up:
Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)
Explanation 1
- In order to calculate the result of one number,
res[i]
, if we know its left side product and right side prodcut, then we can easily calculateres[i] = fwd[i] * bwd[i]
. So, we should create two arraysfwd[i]
to representnums[i]
’s left side product,bwd[i]
to representnums[i]
’s right side product. After we calculatefwd[]
andbwd[]
, then we can calculateres[]
.
Solution 1
1 |
|
Explanation 2
- We can also save space by using
res[]
to replace thefwd[]
, in other word, we calculate the left side product and save tores[]
. Then, we create a variableright
initialize to 1 and represent the right side product, then loop from right to left to updateres[i] = res[i] * right
, and updateright = nums[i] * right
in each iteration.
Solution 2
1 |
|
Valid Parenthesis String
Given a string containing only three types of characters: ‘(‘, ‘)’ and ‘*’, write a function to check whether this string is valid. We define the validity of a string by these rules:
-
Any left parenthesis
'('
must have a corresponding right parenthesis')'
. -
Any right parenthesis
')'
must have a corresponding left parenthesis'('
. -
Left parenthesis
'('
must go before the corresponding right parenthesis')'
. -
'*'
could be treated as a single right parenthesis')'
or a single left parenthesis'('
or an empty string. -
An empty string is also valid.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Note:
- The string size will be in the range [1, 100].
Explanation 1
-
If there’s no
*
, then this problem will be very easy. We can solve it by creating a countercnt
. If we have left parenthesis, thencnt += 1
; if we have right parenthesis, thencnt -= 1
. Whencnt
is less than 0, we returnfalse
. At the end, we check ifcnt
is equal to 0. -
Now, we have the
*
. Ifcnt
is less than 0, we can use the*
to represent the left parenthesis to make ittrue
. So when can we use the*
to represent left parenthesis? We have two cases:* )
and* (
. In the first case, we can use*
to represent the left parenthesis. In the second case, no matter*
represent left parenthesis or empty string, it still befalse
. -
We can solve this problem using two stacks:
left
stack to record the index of the left parenthesis.star
stack to record the index of the*
. Loop through the string, if the current character is(
, we push it toleft
stack. Else if it’s*
, we push it tostar
stack. Else if the current character is)
, then we check if bothleft
stack andstar
stack are empty, then we returnfalse
. If theleft
stack is not empty, we pop it. Else if thestar
stack is not empty, we pop it. -
After finish looping, we check if both
left
stack andstar
stack are empty or not. If they both are empty, we returntrue
. Else, that means we have extra(
or*
. While both stacks are not empty, each time, we pop both stacks, and compare theleft
stack index andstar
stack index. If the left stack index is greater, that means*
is in front the(
, so we returnfalse
. Outside the while loop, we check if the left stack is empty or not. If left stack is not empty, that means we have extra(
and no*
so we returnfalse
. Else, we returntrue
.
Solution 1
1 |
|
Explanation 2:
-
Since
*
can be represented as left parenthesis or right parenthesis, we can forward loop one time, and backward loop one time to fnd the solution. In forward loop, we represent*
as left parenthesis, in backward loop, we represent*
as right parenthesis. -
In forward loop, if current character is
(
or*
, we increase the counterleft
by 1. If the current character is)
, we decrease the counter. When looping, if the counter is less than 0, that means we have more right parenthesis so we returnfalse
. After forward looping, if the counterleft
is equal to 0, we returntrue
. If the counterleft
is greater than 0, we do not returnfalse
yet since we treat all*
as left parenthesis but*
can actually be represent as empty string. -
After forward loop, we can start backward loop. Now, we represent all
*
as right parenthesis. If current character is)
or*
, we increase the counterright
by 1, else if the current character is(
then we decrease theright
counter by 1. If the counter is less than 0, that means we have more left parenthesis so we returnfalse
. -
At the end of backward loop, we return
true
as the result. The reason is now the counterright
can either be equal to 0 or greater than 0. If it’s equal to 0, we returntrue
because equal number of left parenthesis and right parenthesis. Why the counterright
is greater than 0, but we still returntrue
? The reason is before when we finish the forward loop, we confirm that number of(
plus*
are greater than number of)
. Now theright
is greater than 0 because some right parenthesis are represented by*
.
Solution 2:
1 |
|
Explanation 3:
-
We can also use brute force recursive way to solve this problem. We create a helper function and pass the string itself, the variable
start
to represent the current character index, and the countercnt
. Later, if the current character is(
, we plus 1. If the current character is)
, we subtract 1. -
In the helper function, the base case is if
cnt
is less than 0, we returnfalse
. We loop fromstart
to the end of string, if the current character is(
we plus 1, else if it’s)
, we subtract 1 and check ifcnt
is less than 0, then we returnfalse
. Else if the current character is*
, we recursively check 3 cases: first case is using*
as empty string, second case is using*
as(
, third case is using*
as)
. If either case istrue
, we returntrue
. Outside thefor
loop, we check ifcnt
is equal to 0.
Solution 3:
1 |
|
Explanation 4:
Scan from left to right, and record counts of unpaired ‘(‘ for all possible cases. For ‘(‘ and ‘)’, it is straightforward, just increment and decrement all counts, respectively.
When the character is '*'
, there are three cases, ‘(‘, empty, or ‘)’, we can think those three cases as three branches in the ongoing route.
Take (**())
as an example. There are 6 chars:
-
At step 0: only one count = 1.
-
At step 1: the route will be diverted into three branches, so there are three counts: 1 - 1, 1, 1 + 1 which is 0, 1, 2, for ‘)’, empty and ‘(‘ respectively.
-
At step 2 each route is diverged into three routes again. so there will be 9 possible routes now.
-
For count = 0, it will be diverted into 0 – 1, 0, 0 + 1, which is -1, 0, 1, but when the count is -1, that means there are more ‘)’s than ‘(‘s, and we need to stop early at that route, since it is invalid. we end with 0, 1.
-
For count = 1, it will be diverted into 1 – 1, 1, 1 + 1, which is 0, 1, 2
-
For count = 2, it will be diverted into 2 – 1, 2, 2 + 1, which is 1, 2, 3
-
To summarize step 2, we end up with counts of 0,1,2,3
At step 3, increment all counts –> 1,2,3,4
At step 4, decrement all counts –> 0,1,2,3
At step 5, decrement all counts –> -1,0,1,2, the route with count -1 is invalid, so stop early at that route. Now we have 0,1,2.
In the very end, we find that there is a route that can reach count == 0. Which means all ‘(‘ and ‘)’ are cancelled. So, the original String is valid.
Another finding is counts of unpaired ‘(‘ for all valid routes are consecutive integers. So we only need to keep a lower and upper bound of that consecutive integers to save space.
One case doesn’t show up in the example is: if the upper bound is negative, that means all routes have more ‘)’ than ‘(‘ –> all routes are invalid –> stop and return false.
Solution 4:
1 |
|
Source: https://leetcode.com/problems/valid-parenthesis-string/discuss/107577/Short-Java-O(n)-time-O(1)-space-one-pass
Number of Islands
Given a 2d grid map of '1'
s (land) and '0'
s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
1 |
|
Example 2:
1 |
|
Explanation 1
-
We can use DFS and a visited array to solve this problem.
-
Loop through every element in the two dimensional array, if the element is
1
and it’s not visited, then we start our flood fill dfs helper function to update the visited array. Then, we increase our result counter by 1. -
At the end, we return our result.
Solution 1
1 |
|
Explanation 2
-
We can also use BFS to solve this problem. In order to use BFS, we need a queue. We still need to iterate the 2d grid. When the current grid element is 1, we increase the result by 1 and mark its coordinate in the visited 2d array to true. Then, we push the current grid element’s total value (curRow * numOfColumn + curCol) into the queue.
-
While the queue is not empty, we pop out the total value and use the total value to get back the curRow and curCol. Then we we iterate 4 times, each time we get its updated surrounding position (left, top, right, bottom). If the updated surrounding position is inside the grid and it’s not visited and its value is 1, then we mark the updated position as visited, and then push it to the queue. Repeat until the queue is empty.
Solution 2
1 |
|
Explanation 3
-
This is a disjoin set or union find problem.
-
First, we creat an array
parent[]
that has sizerow * col
, and a variablecnt
. Loop through every element, if the current element is1
, then we increasecnt
and updateparent[i] = i
. -
Next, we loop through every element again, this time if the current element is
1
, then we check its 4 neighbor directions. If its neighbor is not out of bound and its element is also1
, then we find the current element’s parent and its neighbor’s parent. If both parent is not the same, we union both parents and subractcnt
by 1. -
At the end, we return
cnt
as the result.
Solution 3
1 |
|
From: [LeetCode] 200. Number of Islands
Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example:
1 |
|
Explanation 1
-
Similar to 62. Unique Paths, we can create a
dp[][]
and use dynamic programming to solve this problem. -
The base case is
dp[0][0]
has the same value asgrid[0][0]
. The top row element will be its current value plus its left value,dp[0][col] = grid[0][col] + dp[0][col-1]
. The left most column element will be its current value plus its top value,dp[row][0] = grid[row][0] + dp[row-1][0]
. -
Now, we need to find the function. The function to calculate
dp[row][col]
will be its current value plus the minimum between its top value and its left value. In other word,dp[row][col] = grid[row][col] + min(dp[row-1][col], dp[row][col-1])
. -
The result will be the bottom right element of dp, which is
dp[row-1][col-1]
.
Solution 1
1 |
|
Explanation 2
-
We can save by space by using a 1 dimensional array
dp[]
that has sizecol
. Initialize all its elements asINT_MAX
exceptdp[0] = 0
. The reason we can use the 1 dimensional array is the current element’s min sum is only depends on its left and top element’s min sum. -
We don’t need to calculate the min sum of the first row and first column. Instead, when we iterate, if
c == 0
that means its first column, so we can updatedp[c] = grid[r][c] + dp[c]
. Else, we need to compare the left element’sdp[c-1]
and top element’sdp[c]
and choose the minimum one. If the current element is on the first row,dp[c]
is theINT_MAX
, so we will choose the minimumdp[c-1]
which is on the left side, then plus the current elementgrid[r][c]
, sodp[c] = grid[r][c] + min(dp[c], dp[c-1])
.
Solution 2
1 |
|
Explanation 3
- We can also save space by replacing the
grid
element. We need to iterate every element. If the current element isgrid[0][0]
, then wecontinue
. Else ifr == 0
, then we update the current element plus its left element. Else ifc == 0
, then we update the current element plus its top element. Else, we update the current element plus the minimum of its left and top element.
Solution 3
1 |
|
From: [LeetCode] 64. Minimum Path Sum
Search in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
You are given a target value to search. If found in the array return its index, otherwise return -1
.
You may assume no duplicate exists in the array.
Your algorithm’s runtime complexity must be in the order of O(log n).
Example 1:
1 |
|
Example 2:
1 |
|
Explanation
-
For example, the array is [3, 4, 5, 6, 7, 8, 9, 1, 2], the middle element is 7. We can draw the graph like below:
1
2
3
4
5
6
7
8
9/ / /(mid) / / / /(left = 3) /(right = 2) /
-
We need to consider two cases, case1, the
mid
is greater thanleft
, case2 is themid
is less thanleft
. The above example is case1. In case1, if thetarget
is greater thanleft
andtarget
is less thanmid
, then we can setright = mid
, else, we setleft = mid
. Then, we recusivly find themid
and check again. In case2, iftarget
is less thanright
andtarget
is greater thanmid
, then we can setleft = mid
, else, we setright = mid
. Then, we also recursivly find themid
and check again. -
When the
left
andright
is next to each other, we can break out the loop, and checkleft
andright
individually. If not found thetarget
, we return -1.
From: [LeetCode] 33. Search in Rotated Sorted Array
Solution
1 |
|
Construct Binary Search Tree from Preorder Traversal
Return the root node of a binary search tree that matches the given preorder
traversal.
(Recall that a binary search tree is a binary tree where for every node, any descendant of node.left
has a value <
node.val
, and any descendant of node.right
has a value >
node.val
. Also recall that a preorder traversal displays the value of the node
first, then traverses node.left
, then traverses node.right
.)
Example 1:
1 |
|
Note:
1 <= preorder.length <= 100
- The values of
preorder
are distinct.
Explanation 1
-
Since the input array is preorder traversal, so the first element is the root. From the problem’s example,
8
will be the root. How do we knowroot.left
androot.right
?root.left = 5
because 5 is the next element of 8, and 5 is less than 8. To findroot.right
, we need to loop from the second element to the right until the current element is greater than the root, which is10
from the above example. -
Now we know
[5, 1, 7]
will be in the left subtree,[10, 12]
will be in the right subtree. We can create a helper method, pass the input array, and two variablesstart
andend
which represent the range of the subarray. This helper method will recursively create the binary search tree for the left subtree and right subtree.
Solution 1
1 |
|
Explanation 2
-
We can also solve this problem in $O(n)$ runtime by using a global index
i
to represent the current index of the input array. Reading the problem, 5 is the left child or 8, 1 is the left child of 5, …, 7 cannot be the left child of 1 since 7 > 1, and 7 cannot be the right child of 1 since 7 > 5, but 7 can be the right child of 5 since 7 < 8. -
We can create a helper method, pass in the input array and the upper bound variable
bound
which initialize toINT_MAX
. In the helper method, we create the root node,root.left
will have the upper bound ofroot.val
, androot.right
will have the upper bound ofbound
. The base case is ifi == len(preorder)
orpreorder[i] > bound
, then we return NULL.
Solution 2
1 |
|
Leftmost Column with at Least a One
(This problem is an interactive problem.)
A binary matrix means that all elements are 0
or 1
. For each individual row of the matrix, this row is sorted in non-decreasing order.
Given a row-sorted binary matrix binaryMatrix, return leftmost column index(0-indexed) with at least a 1
in it. If such index doesn’t exist, return -1
.
You can’t access the Binary Matrix directly. You may only access the matrix using a BinaryMatrix
interface:
-
BinaryMatrix.get(x, y)
returns the element of the matrix at index(x, y)
(0-indexed). -
BinaryMatrix.dimensions()
returns a list of 2 elements[m, n]
, which means the matrix ism * n
.
Submissions making more than 1000
calls to BinaryMatrix.get
will be judged Wrong Answer. Also, any solutions that attempt to circumvent the judge will result in disqualification.
For custom testing purposes you’re given the binary matrix mat
as input in the following four examples. You will not have access the binary matrix directly.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Example 4:
1 |
|
Constraints:
-
m == mat.length
-
n == mat[i].length
-
1 <= m, n <= 100
-
mat[i][j]
is either0
or1
. -
mat[i]
is sorted in a non-decreasing way.
Explanation 1
-
New Problem!
-
(Binary Search) For each row do a binary search to find the leftmost one on that row and update the answer.
Solution 1
1 |
|
Explanation 2
- (Optimal Approach) Imagine there is a pointer p(x, y) starting from top right corner. p can only move left or down. If the value at p is 0, move down. If the value at p is 1, move left. Try to figure out the correctness and time complexity of this algorithm.
Solution 2
1 |
|
Week 4: April 22nd–April 28th
Subarray Sum Equals K
Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k.
Example 1:
1 |
|
Note:
-
The length of the array is in range [1, 20,000].
-
The range of numbers in the array is [-1000, 1000] and the range of the integer k is [-1e7, 1e7].
Hint 1:
Will Brute force work here? Try to optimize it.
Hint 2:
Can we optimize it by using some extra space?
Hint 3:
What about storing sum frequencies in a hash table? Will it be useful?
Hint 4:
sum(i,j)=sum(0,j)-sum(0,i), where sum(i,j) represents the sum of all the elements from index i to j-1. Can we use this property to optimize it.
Explanation 1
-
First, we create an accumulation sum array
sums
by coping the input array, then iterate it, each iteration, we updatesums[i] = sums[i-1] + nums[i]
. -
Next, we check all the accumulation sum array and compare with
k
. We iterate this accumulation sum array. First check ifsums[i] == k
, if it’s true, we increase the result. Then, we think ofi
as the ending index of the subarray, loopj
from 0 toi-1
inclusive. We check every accumulate sum arraysums[i] - sums[j]
if it’s equals tok
.
Solution 1
1 |
|
Explanation 2
- Brute force solution. Two loop, loop
i
as the starting index of the subarray,j
as the last index of the subarray,nums[i, j]
and check if all elements inside this array sum tok
.
Solution 2
1 |
|
Explanation 3
-
Hashmap<sum[0, i - 1], frequency>
.1
2sum[i, j] = sum[0, j] - sum[0, i - 1] --> sum[0, i - 1] = sum[0, j] - sum[i, j] k sum hashmapKey --> hashmapKey = sum - k
-
Now, we have
k
andsum
. As long as we can find asum[0, i - 1]
, we then get a valid subarray which is as long as we have the hashmapKey, we then get a valid subarray. -
Initially, hm[0] = 1 because if
k = 7
, we have array[2, -2, 3, -3, 7]
, the answer should be 3. When we iterate to element 7, we havehm[0] = 2
. Since[7]
is also one possible answer andhm[sum - k = 7 - 7 = 0]
, so we initializehm[0] = 1
.
Solution 3
1 |
|
Bitwise AND of Numbers Range
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
Example 1:
1 |
|
Example 2:
1 |
|
Explanation
-
We know that all the numbers in the array are consecutive, so their right most part must be different. For example, 101 and 110 are consecutive numbers, and their right most 2 bit are different. Therefore, we only need to find their same left most bit, in this case is 1. And after 1, there are two bits, so the result is 100, which is 4.
-
We can achieve this by right shift
m
andn
, until they are the same, in other word, we get the common left most bit. While we shifting, we record how many bits we shift. At the end, we shift the same bit to the left to get the result.
Solution
1 |
|
LRU Cache
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and put
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value)
- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
The cache is initialized with a positive capacity.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
1 |
|
Explanation
-
We can use doubly linked list storing class node to achieve adding and removing in $O(1)$ time by using
prev
andnext
pointer. When we do get, we can use hashmap to achieve getting the value by key in $O(1)$ time. -
Besides
put
andget
function, we also need to haveremove
andsetHead
function. If we run get on a node, then that node need to set it as head. If we have number ofcapacity
node in our linked list, then if we put one more node, we need toremove
the tail node.
From: [LeetCode] 146. LRU Cache
Solution
1 |
|
Jump Game
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
Example 1:
1 |
|
Example 2:
1 |
|
Explanation
- First we create a variable
max = 0
to record the maximum position we can reach. Then we iterate the array, updatemax = max(max, i+nums[i])
, ifmax >= nums[len(nums)-1]
, we returntrue
. Else ifi > max
, we break out the loop and returnfalse
.
From: [LeetCode] 55. Jump Game
Solution
1 |
|
Longest Common Subsequence
Given two strings text1
and text2
, return the length of their longest common subsequence.
A subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, “ace” is a subsequence of “abcde” while “aec” is not). A common subsequence of two strings is a subsequence that is common to both strings.
If there is no common subsequence, return 0.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Constraints:
-
1 <= text1.length <= 1000
-
1 <= text2.length <= 1000
The input strings consist of lowercase English characters only.
Explanation
-
We can use dynamic programming to solve this problem. Dynamic init is creating a two dimensional array
dp[r][c]
which represents the length of the longest common subsequence (LCS) fortext1[0 : r]
andtext2[0 : c]
. -
Dynamic base is for
text1
ortext2
that have length 0, then their length of LCS is 0, in other words, for thedp[r][c]
, the top row and the left most column will be 0. -
Dynamic function. If the
r
th index fortext1
and thec
th index fortext2
are the sametext1[r-1] == text2[c-1]
, thendp[r][c] = 1 + dp[r-1][c-1]
. Else,dp[r][c] = max(dp[r-1][c], dp[r][c-1])
. -
Dynamic result is the last index for both
text1
andtext2
indp
which isdp[len(text1), len(text2)]
.
Solution
1 |
|
Maximal Square
Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.
Example:
1 |
|
Explanation 1
-
We can solve this problemm using dynamic programming. For each matrix element except the first row and first column, we think of it as the bottom right point of the square. Also, we will use an extra $m x n$ two dimensional array
dp
to keep track of the max length of the square base on that iterative matrix point. This iterative point, or bottom right point of the square, its maximum square’s lengthdp[r][c]
will depends on its left pointdp[r][c-1]
, top pointdp[r-1][c]
, and top left pointdp[r-1][c-1]
. In other words,dp[r][c]
will be the minimum of its left point level, top point level, and top left point level. But if this iterative matrix point is 0, then its level will be 0, we don’t need to check its left, top, and top left. For every iteration, we keep track of the maximum level or length. When we iterative to the bottom right, we have calculated all the length base on every points. At the end, we will return the square of the maximum length as the result. -
Dynamic init and base is first row and first column don’t change, in other word,
dp[0][c] = matrix[0][c]
,dp[r][0] = matrix[r][0]
. -
Dynamic function is
dp[r][c] = min (dp[r-1][c], dp[r][c-1], dp[r-1][c-1]) + 1
only ifmatrix[r][c] != 0
. Ifmatrix[r][c] = 0
, thendp[r][c] = 0
. -
Dynmaic result is the square of maximum level.
Solution 1
1 |
|
Explanation 2
-
We can save space by using an one dimensional array
dp[r+1]
, which has lengthrow + 1
. This time, we loop from top to bottom, then left to right. We have length plus 1 because we want to avoiddp[r-1]
’sr-1
be negative.dp[r]
means thematrix[r-1][c]
’s maximum side length, sor
will start from 1. -
We know the
top = dp[r-1]
,left = dp[r]
, how do we find outtopLeft
? We first initialize the variabletopLeft = 0
at the beginning of the function,topLeft
is equal to the last iteration’s olddp[r-1]
. In each iteration, we store the olddp[r]
to atemp
variable, after updating the currentdp[r]
, then we updatetopLeft = temp
, so in the next iteration, we havetopLeft
be the last iteration’s olddp[r-1]
.
Solution 2
1 |
|
First Unique Number
You have a queue of integers, you need to retrieve the first unique integer in the queue.
Implement the FirstUnique
class:
-
FirstUnique(int[] nums)
Initializes the object with the numbers in the queue. -
int showFirstUnique()
returns the value of the first unique integer of the queue, and returns -1 if there is no such integer. -
void add(int value)
insert value to the queue.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Constraints:
-
1 <= nums.length <= 10^5
-
1 <= nums[i] <= 10^8
-
1 <= value <= 10^8
-
At most
50000
calls will be made toshowFirstUnique
andadd
.
Hint 1:
Use doubly Linked list with hashmap of pointers to linked list nodes. add unique number to the linked list. When add is called check if the added number is unique then it have to be added to the linked list and if it is repeated remove it from the linked list if exists. When showFirstUnique is called retrieve the head of the linked list.
Hint 2:
Use queue and check that first element of the queue is always unique.
Hint 3:
Use set or heap to make running time of each function O(logn).
Explanation
-
New problem!
-
Similar to [LeetCode] 146. LRU Cache, we need to create a doubly linked list, a
hashmap<Integer, Node>
, ahead
and atail
pointer. We use a doubly linked list because we want to keep all unique numbers in this linked list, and have $O(1)$ time complexity for removing the linked list node. We use a hashmap because we want to know if the input number is appeared before or no. -
For method
showFirstUnique
, we can check if thehead
pointer is null or not. If it’s not null, then we returnhead.val
, else we return-1
. -
For method
add
, if the input number is not appeared before, then we put the number and its corresponding node to the map, then add that node to the doubly linked list astail
. Else if the input number appeared before, then we remove its corresponding node from the linked list.
Solution
1 |
|
Week 5: April 29th–April 30th
Binary Tree Maximum Path Sum
Given a non-empty binary tree, find the maximum path sum.
For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.
Example 1:
1 |
|
Example 2:
1 |
|
Explanation
-
This problem is different from the general path sum problem, in this problem, path sum can starts in non-root, and it can also end in non-leaf.
-
This kind of path can be concluded in two types:
root->leaf
path, in example1’s 1->2 or 1->3.- Two nodes are connected by their lowest common ancestor (LCA) node, in example1’s 2->1->3.
-
Apprently, top-down’s recursion method doesn’t work because in type2’s path, its path sum is depends on LCA’s left and right sub path’s maximum, and this type of path sum cannot be obtained from top-down recursion method.
-
Therefore, we can use bottom-up’s recursion method. Let say node x,
- Define
PS1(x)
is from node x to leaf’s first type’s path sum. - Define
PS2(x)
is node x as LCA’s second type path’s path sum. - So, if we find all node x’s
PS1
andPS2
, then we can find the max path sum.
- Define
-
How to find
PS1(x)
andPS2(x)
?PS1(x)
andPS2(x)
are not less thanx-val
becausex
itself can be a single node path.PS1(x)
andPS2(x)
can be found inPS1(x-left)
andPS1(x-right)
:PS1(x) = max [ max(PS1(x->left), 0), max(PS1(x->right), 0) ] + x->val
PS2(x) = max(PS1(x->left), 0) + max(PS1(x->right), 0) + x->val
-
We need to return
PS1(x)
for its upper layer’s node to calculatePS1
andPS2
. -
For leaf node,
PS1(x) = PS2(x) = x->val
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Solution { public: int maxPathSum(TreeNode *root) { int maxSum = INT_MIN; int ps1_root = findMaxPathSum(root, maxSum); return maxSum; } int findMaxPathSum(TreeNode *root, int &maxSum) { if(!root) return 0; int ps1_left = 0, ps1_right = 0; if(root->left) ps1_left = max(findMaxPathSum(root->left,maxSum),0); if(root->right) ps1_right = max(findMaxPathSum(root->right,maxSum),0); int ps1_root = max(ps1_left, ps1_right) + root->val; int ps2_root = ps1_left + ps1_right + root->val; maxSum = max(maxSum,max(ps1_root, ps2_root)); return ps1_root; } };
From: [LeetCode] 124. Binary Tree Maximum Path Sum
Solution
1 |
|
Check If a String Is a Valid Sequence from Root to Leaves Path in a Binary Tree
Given a binary tree where each path going from the root to any leaf form a valid sequence, check if a given string is a valid sequence in such binary tree.
We get the given string from the concatenation of an array of integers arr
and the concatenation of all values of the nodes along a path results in a sequence in the given binary tree.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Constraints:
-
1 <= arr.length <= 5000
-
0 <= arr[i] <= 9
Each node’s value is between [0 - 9].
Hint 1:
Depth-first search (DFS) with the parameters: current node in the binary tree and current position in the array of integers.
Hint 2:
When reaching at final position check if it is a leaf node.
Explanation 1
-
New problem and last problem of this 30 day pratice!
-
We can use DFS to solve this problem. We pass the root node, the array, and the current index to the helper function.
-
In the helper function, the base case is if the current node is NULL, or the current index is greater than the length of the array, or the current node value is not equal to the current array value, we return false.
-
If the current node is the leaf node and its value is equal to the current element, and the current element is the last element of the array, we return true.
-
If the current node is equal to the current element, but it’s not the leaf node, then we recursively call the helper function with the current node’s left child, and call the helper function with its right child, and the current index increase one.
Solution 1
1 |
|
Explanation 2
-
We can also use BFS to solve this problem. We creat a queue and push the current root node to the queue.
-
Loop the current index from 0 to the last index inclusive and the queue is not empty, then inner loop the queue
len(queue)
times. Each time, we dequeue to get the current node. If the current node’s value is not equal to thearr[curIdx]
, then wecontinue
. Else if the current node is the leaf node and current index is the last index, then we return true. Else, we enqueue the current node’s left and right node to the queue. Outside the loop, we return false.
Solution 2
1 |
|