@242. Valid Anagram
Given two strings s and t, return true if t is an anagram of s, and false otherwise.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Example 1:
Input: s = “anagram”, t = “nagaram”
Output: true
1 <= s.length, t.length <= 5 * 10^4
s and t consist of lowercase English letters.
func isAnagram(s string, t string) bool {
if len(s) != len(t) {
return false
}
var sArr, tArr [26]int
for i := 0; i < len(s); i++ {
// index in sArr is s[i] - 'a'
sArr[s[i] - 'a']++
// index in tArr is t[i] - 'a'
tArr[t[i] - 'a']++
}
return sArr == tArr
}@424. Longest Repeating Character Replacement
You are given a string s and an integer k. You can choose any character of the string and change it to any other uppercase English character. You can perform this operation at most k times.
Return the length of the longest substring containing the same letter you can get after performing the above operations.
Example 1:
Input: s = “ABAB”, k = 2
Output: 4
Explanation: Replace the two ‘A’s with two ‘B’s or vice versa.
1 <= s.length <= 10^5
s consists of only uppercase English letters.
0 <= k <= s.length
Sliding window. (WindowSize - Most frequent Element count in window) = Characters that need to be replaced. If Characters that need to be replaced is greater than k, move left pointer of window.
@11. Container with most water
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container, such that the container contains the most water.
Return the maximum amount of water a container can store.
Notice that you may not slant the container.
Example1:
Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
Two Pointers. Compare left height and right height. Move the lower height one step forward. Compare the previous stored maxArea with the new area.
The logic for moving the pointers:
Scenario A: Moving the one with higher height.
1. We move to a higher height => Doesn’t matter, the height of the area is still determined by the lower one, since we decreased (right - left), the area is smaller.
2. We move to an equal height => Doesn’t matter, the area is smaller due to decreased (right - left).
3. Lower height => Not considerable, we always get a lower height.
Scenario B: Moving the one with the lower height. 1. We move to an equal height => Doesn't matter, the area is smaller due to decreased (right - left). 2. We move to a lower height => Not considerable, we always get a lower height. 3. We move to a higher height => Wwe have a `chance` of getting a greater area, but we don't know more about it since (right - left) is also an issue With all the scenarios given, moving the lower height one step forward and compare with the current max area is the solution.
func maxArea(height []int) int {
area := func(left, right, leftHeight, rightHeight int) int {
// The area is determined by the bottleneck from the lower between leftHeight and rightHeight
return (right - left) * min(leftHeight, rightHeight)
}
i, j := 0, len(height) - 1
// How do we update our left and right pointers?
// Minimum height is the bottleneck, we are trying to find a better bottleneck.
// For example, left height = 1, right height = 7
// We now assume that right height is good, and we want to optimize the answer by finding a better left height, move left height and compare again.
var maxArea int
for i < j {
maxArea = max(maxArea, area(i, j, height[i], height[j]))
if height[i] < height[j] {
i++
} else {
j--
}
}
return maxArea
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}@Permutation in String
Given two strings s1 and s2, return true if s2 contains a permutation of s1, or false otherwise.
In other words, return true if one of s1’s permutations is the substring of s2.
Example 1:
Input: s1 = “ab”, s2 = “eidbaooo”
Output: true
Explanation: s2 contains one permutation of s1 (“ba”).
1 <= s1.length, s2.length <= 10^4
s1 and s2 consist of lowercase English letters.
func checkInclusion(s1 string, s2 string) bool {
windowSize := len(s1)
if len(s2) < windowSize {
return false
}
// Create two arrays to compare.
var s1Arr [26]int
for i := range s1 {
// All lowercases. rune 'a' is 97. rune 'b' is 98. 98-97 means adding one to bucket 1 in the array.
s1Arr[s1[i] - 'a']++
}
var s2Arr [26]int
var prevHeadIndex int
for r := range s2 {
// Remove head from s2Arr.
prevHeadIndex = r - windowSize
if prevHeadIndex >= 0 {
s2Arr[s2[prevHeadIndex] - 'a']--
}
// Add current new element to s2Arr. r is the new tail index.
s2Arr[s2[r] - 'a']++
if s1Arr == s2Arr {
return true
}
}
return false
}@155. Min Stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Implement the MinStack class:
You must implement a solution within O(1) time for each function
-2^31 <= val <= 2^31 - 1
Methods pop, top and getMin operations will always be called on non-empty stacks.
At most 3 * 10^4 calls will be made to push, pop, top, and getMin.
Create a normal stack and a monotonic decreasing stack that keeps track of the minimum values. The minimum value is always the rightmost value of the monotonic decreasing stack.
@191. Number of 1 Bits.
Write a function that takes the binary representation of a positive integer and returns the number of set bits it has (also known as the Hamming weight).
Example 1:
Input: n = 11
Output: 3
Explanation:
The input binary string 1011 has a total of three set bits.
Loop the following: Compare unit digits with 1 (0001)using &. Return value will be either 1 ( true ) or 0 ( false ). If result is 1, add one to count.
func hammingWeight(n int) int {
var ones int
// AND with 1.
for n != 0 {
if n & 1 == 1 {
ones++
}
n >>= 1
}
return ones
}& and»_space;
@150. Evaluate Reverse Polish Notation
You are given an array of strings tokens that represents an arithmetic expression in a Reverse Polish Notation.
Evaluate the expression. Return an integer that represents the value of the expression.
Example 1:
Input: tokens = [“2”,”1”,”+”,”3”,”*”]
Output: 9
Explanation: ((2 + 1) * 3) = 9
Create a stack that supports Pop().
Do the following recursively until the left and right value of the first operator is generated:
Pop() last token ( Head ) from stack.
If the token is an Operator, find left and right recursively.
Ex: [4, 3, *, 13, 5, /, +]
stack = [4, 3, *, 13, 5, /, +]
first op = +, stack = [4, 3, *, 13, 5, /]
left = eval([4, 3, *, 13, 5, /])
second op = /
left = 5, right = 13, return 2, stack = [4, 3, *]
right = eval([4, 3, 8])
third op = *
left = 4, right = 3, return 12, stack = []
firstOp = +, left = 2, right = 12, return 14.
@22 Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
Example 1:
Input: n = 3
Output: [”((()))”,”(()())”,”(())()”,”()(())”,”()()()”]
1 <= n <= 8
Backtracking. Keep track of the open and closing parentheses counts.
* Only add Open parentheses if openCount < n
* Only add a closing parentheses if closeCount < openCount
* Valid if openCount == closeCount == n, return
func generateParenthesis(n int) []string {
open, close := "(", ")"
openCount, closeCount := 1, 0
result := make([]string, 0)
// Declare the function
var generate func(openCount, closeCount int, currStr string)
// Define the function
generate = func(openCount, closeCount int, currStr string) {
if openCount > n {
// End the recursive call when openCount exceeds n: Too many Open Brackets.
return
}
if closeCount > openCount {
// End the recursive call when closeCount exceeds openCount: Too many Close Brackets.
return
}
// Append to result (this is a shared slice) when we reach a valid string.
if openCount == n && closeCount == n {
result = append(result, currStr)
return
}
generate(openCount+1, closeCount, fmt.Sprintf("%s%s",currStr, open))
generate(openCount, closeCount+1, fmt.Sprintf("%s%s",currStr, close))
}
// Start generating strings from '('.
generate(openCount, closeCount, "(")
return result
}Backtracking is used when we need to check all the possible conditions and also want to cut the check early off. It is basically a depth first search with conditions.
@739 Daily Temperature
Given an array of integers temperatures represents the daily temperatures, return an array answer such that answer[i] is the number of days you have to wait after the ith day to get a warmer temperature. If there is no future day for which this is possible, keep answer[i] == 0 instead.
Example 1:
Input: temperatures = [73,74,75,71,69,72,76,73]
Output: [1,1,4,2,1,1,0,0]
Example 2:
Input: temperatures = [30,40,50,60]
Output: [1,1,1,0]
Create a stack that stores the index of days that haven’t met it’s condition. Compare the head ( temperatures[s.head()] ) with todays temperature. If the teperature is greater than the head, pop the head from the stack (meaning that it reaches condition and doesn’t have to be compared again). The days would be today - the day it was stored in the stack (todayIdx - storedIdx).
func dailyTemperatures(temperatures []int) []int {
result := make([]int, len(temperatures))
s := make(stack, 0)
for idx, t := range temperatures {
for s.length() > 0 && t > temperatures[s.head()] {
poppedIdx := s.pop()
result[poppedIdx] = idx - poppedIdx
}
// Add the current number to stack
s.push(idx)
}
return result
}
type stack []int
func (s *stack) push(num int) {
*s = append(*s, num)
}
func (s *stack) pop() int {
if s.length() > 0 {
poppedIndex := (*s)[len(*s) - 1]
*s = (*s)[:len(*s) - 1]
return poppedIndex
}
return -1
}
func (s *stack) length() int {
return len(*s)
}
func (s *stack) head () int {
return (*s)[len(*s) - 1]
}Stack is crazy.
@853 Car Fleet
There are n cars going to the same destination along a one-lane road. The destination is target miles away.
You are given two integer array position and speed, both of length n, where position[i] is the position of the ith car and speed[i] is the speed of the ith car (in miles per hour).
A car can never pass another car ahead of it, but it can catch up to it and drive bumper to bumper at the same speed. The faster car will slow down to match the slower car’s speed. The distance between these two cars is ignored (i.e., they are assumed to have the same position).
A car fleet is some non-empty set of cars driving at the same position and same speed. Note that a single car is also a car fleet.
If a car catches up to a car fleet right at the destination point, it will still be considered as one car fleet.
Return the number of car fleets that will arrive at the destination.
Example 1:
Input: target = 12, position = [10,8,0,5,3], speed = [2,4,1,1,3]
Output: 3
Explanation:
The cars starting at 10 (speed 2) and 8 (speed 4) become a fleet, meeting each other at 12.
The car starting at 0 does not catch up to any other car, so it is a fleet by itself.
The cars starting at 5 (speed 1) and 3 (speed 3) become a fleet, meeting each other at 6. The fleet moves at speed 1 until it reaches target.
Note that no other cars meet these fleets before the destination, so the answer is 3.
n == position.length == speed.length
1 <= n <= 10^5
0 < target <= 10^6
0 <= position[i] < target
All the values of position are unique.
0 < speed[i] <= 10^6
Sort the car by position. The ones that are closer to the target are the dominating ones. If a second car reaches the target faster than the dominating one, it joins the fleet. Thus create a monotonic increasing stack that stores the time to destination for dominating cars. Only update when the time to the destination for a second car is greater than the head of the stack (the current dominating car), meaning that the car is slower and cannot catch up, this itself is a new fleet.
(position, speed, timeToTarget)
cars =
(10, 2, 1) sort (0,1,12)
(8, 4, 1) (3,3, 3)
(0, 1, 12) (5,1,7)
(5, 1, 7) (8,4,1)
(3, 3, 3) (10,2,1)
(0,1)–(3,3)–(5,1)—(8,4)–(10, 2)—12>
dom dom dom
func carFleet(target int, position []int, speed []int) int {
// fleets is a stack that stores the dominating fleet throughout the process.
// It is a monotonically increasing stack.
f := make(fleets, 0)
c := cars{
pos: position,
speed: speed,
}
// Sort the cars by position. The ones that are closer to the target are the dominators to the previous one.
sort.Sort(c)
c.timeToDest = make([]float64, len(c.pos))
for idx := range c.pos {
c.timeToDest[idx] = float64(target - c.pos[idx]) / float64(c.speed[idx])
}
for i := len(c.timeToDest) - 1; i >= 0; i-- {
// Only push the time to the stack when the stack is empty or the time to the destination is greater than the previous one (head)
// We ignore the time to target that is faster than the dominating one => Meaning that it joins the fleet ahead.
if len(f) == 0 || c.timeToDest[i] > f.head() {
f.push(c.timeToDest[i])
}
}
return len(f)
}
type cars struct {
pos []int
speed []int
timeToDest []float64
}
func (c cars) Len() int { return len(c.pos) }
func (c cars) Less(i, j int) bool { return c.pos[i] < c.pos[j] }
func (c cars) Swap(i, j int) {
c.pos[i], c.pos[j] = c.pos[j], c.pos[i]
c.speed[i], c.speed[j] = c.speed[j], c.speed[i]
}
type fleets []float64
func (f *fleets) push(timeToDest float64) {
*f = append(*f, timeToDest)
}
func (f *fleets) head() float64 {
if len(*f) > 0 {
return (*f)[len(*f)-1]
}
return -1.0
}@74 Search a 2D Matrix
You are given an m x n integer matrix matrix with the following two properties:
Each row is sorted in non-decreasing order.
The first integer of each row is greater than the last integer of the previous row.
Given an integer target, return true if target is in matrix or false otherwise.
You must write a solution in O(log(m * n)) time complexity.
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
Output: true
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-10^4 <= matrix[i][j], target <= 10^4
Binary search the row first. Then Binary search the number within the target row. Check edge cases first (Out of bound and greater than the head of the tail row.). If the target is greater or equal to the head of the midRow, move headRow to mid, else, move the tailRow below mid(cuz it is not encluded).
@704 Binary Search
Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1.
You must write an algorithm with O(log n) runtime complexity.
1 <= nums.length <= 10^4
-10^4 < nums[i], target < 10^4
All the integers in nums are unique.
nums is sorted in ascending order.
Binary search. Take special care for the boundary. Always use inclusive for both ends. ‘<=’ is for arrays that only has one element.
func search(nums []int, target int) int {
// Head and tail all inclusive.
// Everything left of head is smaller than target, everything right of tail is greater or equal to the target.
head, tail := 0, len(nums) - 1
var mid int
// '<=' is for arrays that only has one element.
for head <= tail {
mid = (head + tail) / 2
switch {
case nums[mid] == target:
return mid
case nums[mid] > target:
tail = mid - 1
case nums[mid] < target:
head = mid + 1
}
}
return -1
}@875 Koko Eating Bananas
Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours.
Koko can decide her bananas-per-hour eating speed of k. Each hour, she chooses some pile of bananas and eats k bananas from that pile. If the pile has less than k bananas, she eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k such that she can eat all the bananas within h hours.
Example 1:
Input: piles = [3,6,7,11], h = 8
Output: 4
Example 2:
Input: piles = [30,11,23,4,20], h = 5
Output: 30
Binary search. Search for all possible value util the lowest k is found. k starts from 1 and will never exceed the maximum value in piles.
func minEatingSpeed(piles []int, h int) int {
// k starts from 1 an will never exceed the maximum value in piles.
head, tail := 1, maxInPiles(piles) // O(n)
var mid, n int
for head < tail { // O(n^2)
mid = (head + tail) / 2
n = need(piles, mid) // O(n)
switch {
case n > h:
head = mid + 1
case n <= h:
// Always looking for a smaller k, we might have a smaller one on the left.
tail = mid
}
}
return tail
}
func maxInPiles(piles []int) int {
maximum := piles[0]
for i := range piles {
maximum = max(maximum, piles[i])
}
return maximum
}
func need(piles []int, possibleK int) int {
var n int
for i := range piles {
n += int(math.Ceil(float64(piles[i])/ float64(possibleK)))
}
return n
}
Take care of the bounds. It’s tricky.
@2 Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
The number of nodes in each linked list is in the range [1, 100].
0 <= Node.val <= 9
It is guaranteed that the list represents a number that does not have leading zeros.
Create a new node that traverses when the nodes are adding.
In 10 based system there will be addOns, which will always be 1.
The value of the node will be either
* When l1 != nil && l2 != nil, value = l1.Val + l2.Val + addOn
* When l1 == nil && l2 != nil, value = l2.Val + addOn
* When l1 != nil && l2 == nil, value = l1.Val + addOn
* When both is empty, it’s out of the loop.
After it is out of the loop, if the addOn is not zero, create a new node with value 1 (When the value of the last node is greater than 10, 要進位)
@138 Copy List With Random Pointer
A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.
Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list.
For example, if there are two nodes X and Y in the original list, where X.random –> Y, then for the corresponding two nodes x and y in the copied list, x.random –> y.
Return the head of the copied linked list.
The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:
val: an integer representing Node.val
random_index: the index of the node (range from 0 to n-1) that the random pointer points to, or null if it does not point to any node.
Your code will only be given the head of the original linked list.
Ex1:
Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]
0 <= n <= 1000
-104 <= Node.val <= 10^4
Node.random is null or is pointing to some node in the linked list.
Since we cannot point to the orginal one, we have to have the address of the new nodes to point to. Create a hashmap that stores the relationship between the old and new (a <-> a’). Use the relations to get temp.Random’ from temp.Random.
13 (temp) -> 13’ (newNode)
|
v
7 (temp.Random)
and since we know who 7 points to (7’), we can know who 13’ should point to, which is 7’, fetched by 7.
func copyRandomList(head *Node) *Node {
relations := make(map[*Node]*Node)
dummy := new(Node)
nNode := dummy
temp := head
for temp != nil {
// Create newNode
newNode := &Node{Val: temp.Val}
relations[temp] = newNode
// Assign to the next node
nNode.Next = newNode
// Jump to next node.
nNode = nNode.Next
temp = temp.Next
}
temp = head
nNode = dummy.Next
for temp != nil {
nNode.Random = relations[temp.Random]
temp = temp.Next
nNode = nNode.Next
}
return dummy.Next
}The relations between new and old!
@19 Remove Nth Node From End of List
Given the head of a linked list, remove the nth node from the end of the list and return its head.
Example1:
Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]
Example2:
Input: head = [1,2,3,4,5], n = 5
Output: [2,3,4,5]
The number of nodes in the list is sz.
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
Count the length of the list first.
If n == length, remove the head (return head.Next); else traverse till the previous one, change the next of the previous one to the next of the next node (temp.Next = temp.Next.Next).
func removeNthFromEnd(head *ListNode, n int) *ListNode {
listLength := length(head)
if n == listLength {
return head.Next
}
prevIdx := listLength - n - 1
var idx int
temp := head
for temp != nil {
if idx == prevIdx {
temp.Next = temp.Next.Next
}
temp = temp.Next
idx++
}
return head
}
func length(head *ListNode) int {
var count int
temp := head
for temp != nil {
count++
temp = temp.Next
}
return count
}@141 Linked List Cycle
Given head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail’s next pointer is connected to. Note that pos is not passed as a parameter.
Return true if there is a cycle in the linked list. Otherwise, return false.
Example1:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).
The number of the nodes in the list is in the range [0, 104].
-10^5 <= Node.val <= 10^5
pos is -1 or a valid index in the linked-list.
func hasCycle(head *ListNode) bool {
nodeSet := make(map[*ListNode]struct{})
temp := head
var exist bool
for temp != nil {
if _, exist = nodeSet[temp]; exist {
return true
} else {
nodeSet[temp] = struct{}{}
}
temp = temp.Next
}
return false
}func hasCycle(head *ListNode) bool {
fast, slow := head, head
for fast != nil && fast.Next != nil && slow != nil {
fast = fast.Next.Next
slow = slow.Next
if fast == slow {
return true
}
}
return false
}@287 Find the Duplicate Number
Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant extra space.
Example 1:
Input: nums = [1,3,4,2,2]
Output: 2
1 <= n <= 10^5
nums.length == n + 1
1 <= nums[i] <= n
All the integers in nums appear only once except for precisely one integer which appears two or more times.
func findDuplicate(nums []int) int {
var slow, fast int
// Find the intersection point of the two pointers
for {
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast {
break
}
}
// Find the entrance to the cycle
slow = 0
for slow != fast {
slow = nums[slow]
fast = nums[fast]
}
return slow
}
func findDuplicate(nums []int) int {
set := make(map[int]struct{})
for i := range nums {
if _, ok := set[nums[i]]; ok {
return nums[i]
} else {
set[nums[i]] = struct{}{}
}
}
return 0
}func findDuplicate(nums []int) int {
sort.Ints(nums)
for i := 1; i < len(nums); i ++ {
if nums[i] == nums[i - 1] {
return nums[i]
}
}
return 0
}Floyd’s Cycle Detection is the best
@146 LRU Cache
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
Implement the LRUCache class:
LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
int get(int key) Return the value of the key if the key exists, otherwise return -1.
void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.
The functions get and put must each run in O(1) average time complexity.
Example 1:
Input
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]
Create a data structure that can store the timestamp of the keys.
Get(): If key is in cache, update timestamp (For doubly linked List, move key to head). Else, return -1.
Put(): If key is in cache, update timestamp. If key not in cache and cache is full, remove the least used element (for a queue it is the head, for the doubly linked list it is the back), delete the last element from cache. Create a new timestamp for element.
type LRUCache struct {
cache map[int]*list.Element
linklist *list.List
capacity int
}
type Obj struct {
Key int
Value int
}
func Constructor(capacity int) LRUCache {
return LRUCache{
cache: make(map[int]*list.Element, capacity),
linklist: list.New(),
capacity: capacity,
}
}
func (this *LRUCache) Get(key int) int {
if elem, ok := this.cache[key]; ok {
// Put the element to head.
this.linklist.MoveToFront(elem)
return elem.Value.(Obj).Value
}
return -1
}
func (this *LRUCache) Put(key int, value int) {
if elem, ok := this.cache[key]; ok {
// If the key is in list, remove the old timestamp.
this.linklist.Remove(elem)
} else if len(this.cache) == this.capacity {
// Reached Capacity
// Last element of the linked list is the least used.
leastUsedEle := this.linklist.Back()
// Remove the last element from the list.
this.linklist.Remove(leastUsedEle)
// Remove the last element from the map.
delete(this.cache, leastUsedEle.Value.(Obj).Key)
}
// Create a new obj
newObj := Obj{
Key: key,
Value: value,
}
newEle := this.linklist.PushFront(newObj) // New Obj is the recently used, put to head.
this.cache[key] = newEle
return
}We have list in Go Standard Library. It updates the node by directly updating the Next, and Prev pointer.
MoveToFront: O(1)
Remove:O(1)
PushFront: O(1)
@226 Invert Binary Tree
Given the root of a binary tree, invert the tree, and return its root.
Example 1:
Input: root = [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]
Rotate recursively. Observe the base case, where the recursive function should end.
Base case: When node is nil.
Rotate left and right.
func invertTree(root *TreeNode) *TreeNode {
// If node is nil, return nil. Else rotate left and right.
if root != nil {
root.Left, root.Right = invertTree(root.Right), invertTree(root.Left)
return root
}
return nil
}@104 Maximum Depth of Binary Tree
Given the root of a binary tree, return its maximum depth.
A binary tree’s maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: 3
The number of nodes in the tree is in the range [0, 104].
-100 <= Node.val <= 100
Add height recursively. Add 1 at every layer when node is not nil. Compare the maxDepth(node.Left) and maxDepth(node.Right) before adding it to the current height.
Base Case: When node is nil, then maxDepth(nil) = 0
func maxDepth(root *TreeNode) int {
// DFS.
if root == nil {
return 0
}
return 1 + max(maxDepth(root.Left), maxDepth(root.Right))
}Always think of the base case first.
@543 Diameter of Binary Tree
Given the root of a binary tree, return 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.
The length of a path between two nodes is represented by the number of edges between them.
The number of nodes in the tree is in the range [1, 10^4].
-100 <= Node.val <= 100
Compare the diameter and the local diameter recursively.
Diameter = CurrMaxLeftHeight, CurrMaxRightHeight
Return max(currMaxLeftHeight, currMaxRightHeight) to the parent. The parent will use it as either it’s currMaxLeftHeight or currMaxRightHeight.
func diameterOfBinaryTree(root *TreeNode) int {
var diameter int
// dfs finds the maxDepth of each node and compares the local diameter with the stored diameter.
// Local diameter is the leftHeight + rightHeight.
// Only add 1 to the height when a leaf exist.
var dfs func(node *TreeNode) int
dfs = func(node *TreeNode) int {
var leftHeight, rightHeight int
if node.Left != nil {
leftHeight = dfs(node.Left) + 1
}
if node.Right != nil {
rightHeight = dfs(node.Right) + 1
}
diameter = max(diameter, leftHeight + rightHeight)
return max(leftHeight, rightHeight)
}
dfs(root)
return diameter
}Diameter = leftHeight + rightHeight
@110 Balanced Binary Tree
Given a binary tree, determine if it is
height-balanced.
Ex1:
Input: root = [3,9,20,null,null,15,7]
Output: true
A height-balanced binary tree is a binary tree in which the depth of the two subtrees of every node never differs by more than one.
The number of nodes in the tree is in the range [0, 5000].
-10^4 <= Node.val <= 10^4
Do the following recursively until the base case: Check the height difference every layer. If height difference is smaller than 2, the node is balanced. Return the height of the subroot to the next layer, and compare again.
func isBalanced(root *TreeNode) bool {
// Return height, isBalanced
var dfs func(node *TreeNode) (int, bool)
dfs = func(node *TreeNode) (int, bool) {
if node == nil {
return 0, true
}
leftHeight, leftIsBalanced := dfs(node.Left)
rightHeight, rightIsBalanced := dfs(node.Right)
if leftHeight - rightHeight >= 2 || rightHeight - leftHeight >= 2 {
return -1, false
}
return max(leftHeight, rightHeight) + 1, leftIsBalanced && rightIsBalanced
}
_, rootBalanced := dfs(root)
return rootBalanced
}Depth First Search
@100 Same Tree
Given the roots of two binary trees p and q, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.
Ex1:
Input: p = [1,2,3], q = [1,2,3]
Output: true
Ex2:
Input: p = [1,2], q = [1,null,2]
Output: false
The number of nodes in both trees is in the range [0, 100].
-10^4 <= Node.val <= 10^4
Do the following recursively until the base case: Check if the node value is the same. If the node value is the same, compare the children.
func isSameTree(p *TreeNode, q *TreeNode) bool {
if p == nil && q == nil {
return true
}
// In case one of the nodes is nil.
if p == nil && q != nil {
return false
}
if p != nil && q == nil {
return false
}
return p.Val == q.Val && isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}Depth First Search