It’s been a year since doing LeetCoding challenge. Time flies. Coding in Go for 9 months and coding in JS for the last 3 months. I feel more confident coding in these two languages now, but I feel I still need to improve my algorithm skills. It’s more busy this year, sometimes I didn’t think deeply about each coding problems. Hope things go well this year and need to continue reading books like last year.
Week 1: April 1st - April 7th
Largest Unique Number
Given an array of integers A
, return the largest integer that only occurs once.
If no integer occurs once, return -1.
Example 1:
1 |
|
Example 2:
1 |
|
Note:
-
1 <= A.length <= 2000
-
0 <= A[i] <= 1000
Hint 1:
Find the number of occurrences of each value.
Hint 2:
Use an array or a hash table to do that.
Hint 3:
Look for the largest value with number of occurrences = 1.
Explanation
- We can use brute force to solve this problem. First sort the array. Then loop from the largest number to smallest number. If the large number
A[i]
is not equal to its previous numberA[i-1]
, then we return this large numberA[i]
. WhileA[i] == A[i-1]
, we keep decreasingi
. Outside the loop, we return -1.
Solution
1 |
|
Palindrome Linked List
Given the head
of a singly linked list, return true
if it is a palindrome.
Example 1:
1 |
|
Example 2:
1 |
|
Constraints:
-
The number of nodes in the list is in the range
[1, 10^5]
. -
0 <= Node.val <= 9
Follow up: Could you do it in O(n)
time and O(1)
space?
Explanation 1
-
We can use two pointers technique to get to the middle element of the linked list. We also need a stack to store every slow pointer’s iterated value.
-
Then start from the next element of the middle node, we can compare its value with stack’s pop node value. Note, if there are odd number nodes (
fast.next ==null
) in the linked list, we will pop one node first, then start to compare. If they are not equal, then we return false as the result until we finish moving the slow poitners to the end.
Solution 1
1 |
|
Explanation 2
- After we find the middle node, we can reverse the second half list, in other words, all the nodes from
slow.next
to the end of the list. Then, we can iterate and compare the first half’s node with the second half’s node. If there’s one node different, we returnfalse
. After iteration, we returntrue
as the result.
Solution 2
1 |
|
Ones and Zeroes
You are given an array of binary strings strs
and two integers m
and n
.
Return the size of the largest subset of strs
such that there are at most m
0
’s and n
1
’s in the subset.
A set x
is a subset of a set y
if all elements of x
are also elements of y
.
Example 1:
1 |
|
Example 2:
1 |
|
Constraints:
-
1 <= strs.length <= 600
-
1 <= strs[i].length <= 100
-
strs[i]
consists only of digits'0'
and'1'
. -
1 <= m, n <= 100
Explanation
-
This is a knapsack problem. We can use dynamic programming to solve this problem.
-
Dynamic state. We create a two dimensional array
dp[i][j]
which represents if we havei
zeros andj
ones, the maximum number of strings we can form. -
Dynamic init. All
dp[i][j]
are zeros. -
Dynamic function. We can either choose this string or not choose this string. If we choose the current string, then we have
dp[i][j] = dp[i-zeros][j-ones] + 1
.zeros
means the number of 0s the current string has,ones
means the number of 1s the current string has. If we don’t choose the current string, thendp[i][j]
unchanged. Therefore, the dynamic function isdp[i][j] = max(dp[i][j], dp[i-zeros][j-ones]+1)
. Also, we need to loop from the bottom right to the top left. For the same string, if we loop from top left to bottom right, then we already calculateddp[i-zeros][j-ones]
, let saydp[i-zeros][j-ones]=1
; now when the iteration isdp[i-zeros][j-ones]+1=1+1=2
, which adding the extra previous result, in this casedp[i-zeros][j-ones]
and it’s wrong. Instead, it should bedp[i-zeros][j-ones] + 1 = 0 + 1 = 1
. -
Dynamic result is
dp[m][n]
when we have allm
zeros andn
ones, the maximum string we can form.
Solution
1 |
|
Longest Valid Parentheses
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Constraints:
-
0 <= s.length <= 3 * 10^4
-
s[i]
is'('
, or')'
.
Explanation
- We can loop through the string character by character. If the character is
(
, we push its index to the stack. Else if the character is)
, we pop an element of the stack then the length will be the current index subtract the top element of the stack. If after we pop an element of the stack, the stack become empty, then the length will be the current index subtract the leftmost element. If Before we pop an element of the stack, the stack is empty, then we set the leftmost element to the current index.
1 |
|
Solution
1 |
|
Design Circular Queue
Design your implementation of the circular queue. The circular queue is a linear data structure in which the operations are performed based on FIFO (First In First Out) principle and the last position is connected back to the first position to make a circle. It is also called “Ring Buffer”.
One of the benefits of the circular queue is that we can make use of the spaces in front of the queue. In a normal queue, once the queue becomes full, we cannot insert the next element even if there is a space in front of the queue. But using the circular queue, we can use the space to store new values.
Implementation the MyCircularQueue
class:
-
MyCircularQueue(k)
Initializes the object with the size of the queue to bek
. -
int Front()
Gets the front item from the queue. If the queue is empty, return-1
. -
int Rear()
Gets the last item from the queue. If the queue is empty, return-1
. -
boolean enQueue(int value)
Inserts an element into the circular queue. Returntrue
if the operation is successful. -
boolean deQueue()
Deletes an element from the circular queue. Returntrue
if the operation is successful. -
boolean isEmpty()
Checks whether the circular queue is empty or not. -
boolean isFull()
Checks whether the circular queue is full or not.
Example 1:
1 |
|
Constraints:
-
1 <= k <= 1000
-
0 <= value <= 1000
-
At most
3000
calls will be made toenQueue
,deQueue
,Front
,Rear
,isEmpty
, andisFull
.
Follow up: Could you solve the problem without using the built-in queue?
Explanation
-
For circular queue or array question, after insert an element, the next pointer will always be
(i + 1) % size
. For this problem, we use two pointersbeforeHead
andnextTail
. Also, we usesize
to record the maximum size we can have,cnt
to count how many elements are in the queue, anddata[]
to store the elements. -
We can sovle the easy method first.
isEmpty
andisFull
can be solved usingcnt == 0
andcnt == size
. -
For method
Front()
, we first check if isEmpty, if not empty, then we returndata[beforeHead + 1]
, but we need to module size, so returndata[(beforeHead + 1) % size]
. -
For method
Rear()
, we first check if isEmpty, if not empty, then we returndata[nextTail - 1]
, but we need to module size and avoid negative number, so we returndata[(nextTail - 1 + size) % size]
. -
For method
enQueue
, we first check if isFull, if not full, then we can insert the element into indexnextTail
, then increase nextTail by(nextTail + 1) % size
. Also remember to increasecnt
. -
For method
deQueue
, we first check if isEmpty, if not empty, then we can just increasebeforeHead
by(beforeHead + 1) % size
. Also remember to decreasecnt
.
Solution
1 |
|
Global and Local Inversions
We have some permutation A
of [0, 1, ..., N - 1]
, where N
is the length of A
.
The number of (global) inversions is the number of i < j
with 0 <= i < j < N
and A[i] > A[j]
.
The number of local inversions is the number of i
with 0 <= i < N
and A[i] > A[i+1]
.
Return true
if and only if the number of global inversions is equal to the number of local inversions.
Example 1:
1 |
|
Example 2:
1 |
|
Note:
-
A
will be a permutation of[0, 1, ..., A.length - 1]
. -
A
will have length in range[1, 5000]
. -
The time limit for this problem has been reduced.
Hint 1:
Where can the 0 be placed in an ideal permutation? What about the 1?
Explanation
-
Local inversion is also global inversion. If we find any global version that is
A[i] > A[j]
wherei + 2 <= j
, then we return false. -
Global inversion
A[j]
compares withA[j - 2]
,A[j - 3]
,A[j - 4]
, we can take the maximum ofA[j - 2]
,A[j - 3]
,A[j - 4]
ascurMax
and compares withA[j]
. In other words,max(curMax, A[i])
and compare withA[j]
.
Solution
1 |
|
Minimum Operations to Make Array Equal
You have an array arr
of length n
where arr[i] = (2 * i) + 1
for all valid values of i
(i.e. 0 <= i < n
).
In one operation, you can select two indices x
and y
where 0 <= x, y < n
and subtract 1
from arr[x]
and add 1
to arr[y]
(i.e. perform arr[x] -=1
and arr[y] += 1
). The goal is to make all the elements of the array equal. It is guaranteed that all the elements of the array can be made equal using some operations.
Given an integer n
, the length of the array. Return the minimum number of operations needed to make all the elements of arr equal.
Example 1:
1 |
|
Example 2:
1 |
|
Constraints:
1 <= n <= 10^4
Hint 1:
Build the array arr using the given formula, define target = sum(arr) / n
Hint 2:
What is the number of operations needed to convert arr so that all elements equal target ?
Explanation
-
If
n
is odd, for examplen = 5
, we have[1, 3, 5, 7, 9]
. The average number is 5. We need to subtract 2 from 7 and add 2 to 3, we also need to subtract 4 from 9 and add 4 to 1. Total steps is 2 + 4 = 6. -
If
n
is even, for examplen = 4
, we have[1, 3, 5, 7]
. The average number is 4. We need to subtract 1 from 5 and add 1 to 3, we also need to subtract 3 from 7 and add 3 to 1. Total step is 1 + 3 = 4. -
Let
cnt = n / 2
. Ifn
is odd, the result is the first half even number, sores = cnt * (cnt + 1)
. Ifn
is even, the result is the first half odd number, sores = cnt * cnt
.
Solution
1 |
|
Determine if String Halves Are Alike
You are given a string s
of even length. Split this string into two halves of equal lengths, and let a
be the first half and b
be the second half.
Two strings are alike if they have the same number of vowels ('a'
, 'e'
, 'i'
, 'o'
, 'u'
, 'A'
, 'E'
, 'I'
, 'O'
, 'U'
). Notice that s
contains uppercase and lowercase letters.
Return true
if a
and b
are alike. Otherwise, return false
.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Example 4:
1 |
|
Constraints:
-
2 <= s.length <= 1000
-
s.length
is even. -
s
consists of uppercase and lowercase letters.
Hint 1:
Create a function that checks if a character is a vowel, either uppercase or lowercase.
Explanation
- First create a set of all vowels. Use pointer
i
to count the first half string’s vowels, and use pointerj
to count the second half string’s volwels. Finally, if first half string’s number of vowels equals to second half string’s vowels, return true, else return false.
Solution
1 |
|