Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions 0101-0200/0163_missing_ranges.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# @param {Integer[]} nums
# @param {Integer} lower
# @param {Integer} upper
# @return {Integer[][]}
def missing_ranges(nums, lower, upper)
return [[lower, upper]] if nums.empty?

ans = []

if nums[0] > lower
ans << [lower, nums[0]-1]
end

nums.each_cons(2) { |a, b|
if a < b-1
ans << [a+1, b-1]
end
}

if nums[-1] < upper
ans << [nums[-1]+1, upper]
end

ans
end
28 changes: 28 additions & 0 deletions 1101-1200/1105_filling_bookcase_shelves.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# @param {Integer[][]} books
# @param {Integer} shelf_width
# @return {Integer}
def min_height_shelves(books, shelf_width)
# defining dp[i] as the min height for placing i books (IN ORDER)
dp = Array.new(books.size + 1, Float::INFINITY)
dp[0] = 0
(0...books.size).each { |i|
# for the next i-th book
w, h = books[i]
# we can:
# place it on another level
dp[i+1] = dp[i] + h
# collect books [j..i-1] and place them at the same level, 0 <= j < i
(i-1).downto(0) { |j|
w += books[j][0]
# Note that we need to place books IN ORDER
# so we cannot place the i-th book at the same level of books [j..i-2] which above the (i-1)th book
# therefor, if the width of books [j..i] is out of the shelf width, we stop
break if w > shelf_width

h = [h, books[j][1]].max
dp[i+1] = [dp[i+1], dp[j] + h].min
}
}

dp[books.size]
end
57 changes: 57 additions & 0 deletions 1301-1400/1395_count_number_of_teams.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# @param {Integer[]} rating
# @return {Integer}
def num_teams(rating)
max = rating.max
count = 0

# for each k, there're teams formed by rating[k], previous rating[j] <= rating[k] - 1, and previous ratings[i] < rating[j]
# ........ rating[k]-1 rating[k]
# [i] j k
counter = BinaryIndexedTree.new(max)
accumulate = BinaryIndexedTree.new(max)
(0...rating.size).each { |k|
rate = rating[k]
count += accumulate.range_sum(rate-1)
accumulate.update(rate, counter.range_sum(rate-1))
counter.update(rate, 1)
}

# same as above, but in reverse direction
counter = BinaryIndexedTree.new(max)
accumulate = BinaryIndexedTree.new(max)
(rating.size-1).downto(0) { |k|
rate = rating[k]
count += accumulate.range_sum(rate-1)
accumulate.update(rate, counter.range_sum(rate-1))
counter.update(rate, 1)
}

count
end

class BinaryIndexedTree
attr_reader :counter

def initialize(size)
@size = size
@counter = Array.new(size+1, 0)
end

def update(index, val)
i = index + 1
while i <= @size
@counter[i] += val
i += i & (-i)
end
end

def range_sum(index)
sum = 0
i = index + 1
while i > 0
sum += @counter[i]
i -= i & (-i)
end
sum
end
end
6 changes: 6 additions & 0 deletions 1401-1500/1486_xor_operation_in_an_array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# @param {Integer} n
# @param {Integer} start
# @return {Integer}
def xor_operation(n, start)
n.times.reduce(0) { |acc, i| acc ^= (start + 2*i) }
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# @param {Integer[]} arr
# @param {Integer} m
# @param {Integer} k
# @return {Boolean}
def contains_pattern(arr, m, k)
(0..arr.length-m).each { |i|
pattern = arr[i...i+m]
return true if (k-1).times.all? { |j|
pattern == arr[(i + (j+1)*m)...(i + (j+2)*m)]
}
}
false
end
27 changes: 27 additions & 0 deletions 1601-1700/1653_minimum_deletions_to_make_string_balanced.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# @param {String} s
# @return {Integer}
def minimum_deletions(s)
# at the index i
# ...........(a|b)...
# [ balanced ]
# assume that [0..i-1] is balanced by removing some 'a'/'b'
# there're 3 ways to make [0..i] is also balanced:
# - [1] if 'a' at i then:
# + [1.1] we remove some 'a'/'b' same as [0..i-1] above and remove the 'a' at i
# + [1.2] remove all 'b', let 'a' only
# - [2] if 'b' at i, we remove some 'a'/'b' same as [0..i-1] above, and keep 'b' at i
#

ans = 0 # number of removing some 'a'/'b' so far
b_count = 0 # number of prefix 'b' so far
s.each_char { |c|
if c == 'b'
b_count += 1
# case [2], keep b, the ans so far is still optimal
else
# min of case [1.1] and case [1.2]
ans = [ans + 1, b_count].min
end
}
ans
end
32 changes: 32 additions & 0 deletions 1701-1800/1765_map_of_highest_peak.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# @param {Integer[][]} is_water
# @return {Integer[][]}
def highest_peak(is_water)
r = is_water.size
c = is_water[0].size
result = Array.new(r) { Array.new(c, Float::INFINITY) }

queue = []
(0...r).each { |i|
(0...c).each { |j|
if is_water[i][j] == 1
result[i][j] = 0
queue << [i, j]
end
}
}

directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]
until queue.empty?
i, j = queue.shift
directions.each { |dr, dc|
_i = i + dr
_j = j + dc
next if _i < 0 || _i >= r || _j < 0 || _j >= c

queue << [_i, _j] if result[_i][_j] == Float::INFINITY
result[_i][_j] = [result[_i][_j], result[i][j] + 1].min
}
end

result
end
86 changes: 86 additions & 0 deletions 2001-2100/2045_second_minimum_time_to_reach_destination.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# @param {Integer} n
# @param {Integer[][]} edges
# @param {Integer} time
# @param {Integer} change
# @return {Integer}
def second_minimum(n, edges, time, change)
adj = Hash.new { |h, k| h[k] = [] }
edges.each { |u, v|
adj[u] << v
adj[v] << u
}

costs = Array.new(n+1) { [nil, nil] }
queue = MinHeap.new
queue.add([0, 1])
until queue.empty?
t, u = queue.extract_min
wait = (t/change).odd? ? change - (t % change) : 0
next_t = t + wait + time

adj[u].each { |v|
next if costs[v][1] # already reached 2 times, no need to process

if costs[v][0].nil? # reach the first time
costs[v][0] = next_t
else # reach the second time
costs[v][1] = next_t if costs[v][1].nil? && costs[v][0] < next_t
end

return costs[v][1] if v == n && costs[v][1]

queue.add([next_t, v])
}
end
end

class MinHeap
def initialize
@items = []
end

def add(x)
@items.push(x)
swim_up(@items.size-1)
end

def extract_min
return if empty?

swap(0, @items.size-1)
min = @items.pop()
sink_down(0)
min
end

def empty?
@items.empty?
end

private

def swap(i, j)
temp = @items[i]
@items[i] = @items[j]
@items[j] = temp
end

def sink_down(i)
return if (l = 2*i + 1) >= @items.size
r = l + 1

min = (@items[l] <=> @items[r] || 0) <= 0 ? l : r
if (@items[min] <=> @items[i]) < 0
swap(min, i)
sink_down(min)
end
end

def swim_up(i)
return if (p = (i-1)/2) < 0
if (@items[i] <=> @items[p]) < 0
swap(i, p)
swim_up(p)
end
end
end
19 changes: 19 additions & 0 deletions 2601-2700/2670_find_the_distinct_difference_array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @param {Integer[]} nums
# @return {Integer[]}
def distinct_difference_array(nums)
prefix_diff = []
prefix_appear = Hash.new(false)
(0...nums.size).each { |i|
prefix_appear[nums[i]] = true
prefix_diff[i] = prefix_appear.size
}

suffix_diff = []
suffix_appear = Hash.new(false)
(nums.size-1).downto(0).map { |i|
suffix_diff[i] = suffix_appear.size
suffix_appear[nums[i]] = true
}

(0...nums.size).map { |i| prefix_diff[i] - suffix_diff[i] }
end
93 changes: 93 additions & 0 deletions 3101-3200/3123_find_edges_in_shortest_paths.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# @param {Integer} n
# @param {Integer[][]} edges
# @return {Boolean[]}
def find_answer(n, edges)
adj = Hash.new { |h, k| h[k] = [] }
edges.each { |u, v, w|
adj[u] << [v, w]
adj[v] << [u, w]
}

min_cost_from_source = dijkstra(adj, n, 0)
min_cost_from_target = dijkstra(adj, n, n-1)

edges.map { |u, v, w|
min_cost_from_source[n-1] < Float::INFINITY &&
(min_cost_from_source[u] + w + min_cost_from_target[v] == min_cost_from_source[n-1] ||
min_cost_from_source[v] + w + min_cost_from_target[u] == min_cost_from_source[n-1])
}
end

# https://en.wikipedia.org/wiki/Dijkstra's_algorithm
def dijkstra(graph, n, source)
dist = Array.new(n, Float::INFINITY)
dist[source] = 0

queue = MinHeap.new
queue.add([0, source])
until queue.empty?
cost, v = queue.extract_min
next if cost > dist[v]

graph[v].each { |u, w|
alt = dist[v] + w
if dist[u] > alt
dist[u] = alt
queue.add([alt, u])
end
}
end

dist
end

class MinHeap
def initialize
@items = []
end

def add(x)
@items.push(x)
swim_up(@items.size-1)
end

def extract_min
return if empty?

swap(0, @items.size-1)
min = @items.pop()
sink_down(0)
min
end

def empty?
@items.empty?
end

private

def swap(i, j)
temp = @items[i]
@items[i] = @items[j]
@items[j] = temp
end

def sink_down(i)
return if (l = 2*i + 1) >= @items.size
r = l + 1

min = (@items[l] <=> @items[r] || 0) <= 0 ? l : r
if (@items[min] <=> @items[i]) < 0
swap(min, i)
sink_down(min)
end
end

def swim_up(i)
return if (p = (i-1)/2) < 0
if (@items[i] <=> @items[p]) < 0
swap(i, p)
swim_up(p)
end
end
end