Skip to content

Commit d4cfc5d

Browse files
authored
Merge branch 'master' into master
2 parents 3d43bd7 + 8595376 commit d4cfc5d

File tree

9 files changed

+320
-9
lines changed

9 files changed

+320
-9
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ This is my way of saying - change your interview style. There are lots of smart
1313

1414
| problem | solution |
1515
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
16+
| [Unique binary search trees](https://leetcode.com/problems/unique-binary-search-trees/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/unique_bsts.rb) |
1617
| [House Robber](https://leetcode.com/problems/house-robber/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/house-robber.rb) |
18+
| [Coin change](https://leetcode.com/problems/coin-change/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/coin-change.rb) |
19+
| [Decode Strings](https://leetcode.com/problems/decode-string/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/decode_string.rb) |
20+
| [Wiggle Subsequence](https://leetcode.com/problems/wiggle-subsequence/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/wiggle_subsequence.rb) |
21+
| [Unix path](https://leetcode.com/problems/simplify-path/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/simplify_path.rb) |
1722
| [Array Product](https://leetcode.com/problems/product-of-array-except-self/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/product-of-array.rb) |
1823
| [Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/top-k-elements.rb) |
1924
| [Sum 4 arrays](https://leetcode.com/problems/4sum-ii/description/) | [click](https://github.com/sagivo/algorithms/blob/master/src/4-sum.rb) |
@@ -50,6 +55,7 @@ This is my way of saying - change your interview style. There are lots of smart
5055
| [Range minimum query sparse table algorithm](http://en.wikipedia.org/wiki/Range_minimum_query) | [click](https://github.com/sagivo/algorithms/blob/master/src/rmq.rb) |
5156
| [Insertion Sort](https://en.wikipedia.org/wiki/Insertion_sort) | [click](https://github.com/sagivo/algorithms/blob/master/src/insertion_sort.rb) |
5257
| [Towers of Hanoi using Stack](https://en.wikipedia.org/wiki/Tower_of_Hanoi) | [click](blob/master/src/towers_of_hanoi_with_stack.rb)
58+
| [Tarjan's strongly connected components finder](https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) | [click](https://github.com/sagivo/algorithms/blob/master/src/tarjan.rb) |
5359

5460

5561
# How?

src/coin-change.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# @param {Integer[]} coins
2+
# @param {Integer} amount
3+
# @return {Integer}
4+
def coin_change(coins, amount)
5+
return 0 if coins.empty? or amount <= 0
6+
max = 4000000000
7+
res = Array.new(amount, 0)
8+
9+
(1..amount).each do |am|
10+
res[am] = max
11+
12+
coins.each do |c|
13+
next if c > am
14+
res[am] = [res[am], 1 + res[am - c]].min
15+
end
16+
end
17+
18+
res[amount] == max ? -1 : res[amount]
19+
end
20+
21+
p coin_change([1, 2, 5], 11) # => 3

src/decode_string.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# @param {String} s
2+
# @return {String}
3+
def decode_string(s)
4+
strings = ['']
5+
dups = []
6+
str = ''
7+
i = 0
8+
while i < s.size do
9+
if (s[i].to_i > 0)
10+
j = i+1
11+
j += 1 while s[j] != '['
12+
num = s[i...j].to_i
13+
dups.push(num)
14+
strings.push(str)
15+
i = j+1
16+
elsif s[i] == ']'
17+
num = dups.pop
18+
str = strings.pop
19+
str *= num
20+
prev = strings.pop
21+
strings.push(prev + str)
22+
str = ''
23+
i+=1
24+
elsif s[i] != '['
25+
str = strings.pop || ''
26+
str += s[i]
27+
strings.push(str)
28+
str = ''
29+
i+=1
30+
end
31+
end
32+
33+
return strings.pop
34+
end
35+
36+
p decode_string('2[abc]3[cd]ef') # => abcabccdcdcdef
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
#from http://www.geeksforgeeks.org/dynamic-programming-set-28-minimum-insertions-to-form-a-palindrome/
2-
def min_for_palindrome str, left=0, right=nil
3-
right ||= str.size-1
4-
return Float::INFINITY if left > right
5-
return 0 if left == right or (left == right-1 and str[left] == str[right])
6-
return 1 if left == right-1
7-
if str[left] == str[right] then min_for_palindrome(str, left+1, right-1) else [min_for_palindrome(str,left+1, right), min_for_palindrome(str,left,right-1)].min + 1 end
1+
# #from http://www.geeksforgeeks.org/dynamic-programming-set-28-minimum-insertions-to-form-a-palindrome/
2+
def shortest_palindrome(s)
3+
helper(s, 0, s.size-1)
84
end
95

10-
#test
11-
p min_for_palindrome 'geek' #2 -> kgeegk
6+
def helper(s, i, j)
7+
return 0 if i >= j
8+
if s[i] == s[j]
9+
return helper(s, i+1, j-1)
10+
else
11+
return 1 + [helper(s, i+1, j), helper(s, i, j-1)].min
12+
end
13+
end
14+
15+
p shortest_palindrome('geek') # => 2 (kgeegk)

src/simlify_path.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# @param {String} path
2+
# @return {String}
3+
def simplify_path(path)
4+
dirs = path.split("/")
5+
stack = []
6+
7+
dirs.each do |dir|
8+
next if dir.empty? || dir == "."
9+
if dir == ".."
10+
stack.pop unless stack.empty?
11+
else
12+
stack.push(dir)
13+
end
14+
end
15+
16+
"/" + stack.join("/")
17+
end
18+
19+
p simplify_path("/a/./b/../../c/") # => "/c"

src/target_sum.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# @param {Integer[]} nums
2+
# @param {Integer} s
3+
# @return {Integer}
4+
def find_target_sum_ways(nums, s, i = 0, dp = {})
5+
return dp["#{s}-#{i}"] if dp["#{s}-#{i}"]
6+
if i == nums.size
7+
return dp["#{s}-#{i}"] = s == 0 ? 1 : 0
8+
end
9+
10+
return dp["#{s}-#{i}"] ||=
11+
find_target_sum_ways(nums, s + nums[i], i+1, dp) +
12+
find_target_sum_ways(nums, s - nums[i], i+1, dp)
13+
end
14+
15+
p find_target_sum_ways([1, 1, 1, 1, 1], 3) # => 5

src/tarjan.rb

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
class Node
2+
attr_accessor :name, :idx, :lowlink, :on_stack
3+
4+
def initialize(name)
5+
@name = name
6+
end
7+
8+
def ==(other)
9+
if other.class == Node
10+
other.name == self.name
11+
elsif other.class == String
12+
other == self.name
13+
else
14+
false
15+
end
16+
end
17+
18+
def to_s
19+
@name
20+
end
21+
end
22+
23+
class Edge
24+
attr_accessor :from, :to
25+
26+
def initialize(node_from, node_to)
27+
@from, @to = node_from, node_to
28+
end
29+
30+
def ==(other)
31+
self.from == other.from && self.to == other.to
32+
end
33+
34+
def to_s
35+
"(#{from.to_s} -> #{to.to_s})"
36+
end
37+
end
38+
39+
class Graph
40+
attr_accessor :nodes, :edges, :adjmt
41+
42+
def initialize(load_dict = {})
43+
@nodes = []
44+
@edges = []
45+
@adjmt = {}
46+
47+
if load_dict.size > 0 && load_dict.class == Hash
48+
load_dict.each do |v, edges|
49+
node_from = self.add_node(v)
50+
adjmt[node_from] = []
51+
edges.each do |w|
52+
node_to = self.add_node(w)
53+
adjmt[node_from] << node_to
54+
self.add_edge(v, w)
55+
end
56+
end
57+
end
58+
end
59+
60+
def add_node(node_name)
61+
if nodes.index(node_name)
62+
return nodes[nodes.index(node_name)]
63+
else
64+
node = Node.new(node_name)
65+
nodes << node
66+
return node
67+
end
68+
end
69+
70+
def add_edge(node_name_from, node_name_to)
71+
node_from = nodes[nodes.index(node_name_from)]
72+
node_to = nodes[nodes.index(node_name_to)]
73+
edges << Edge.new(node_from, node_to)
74+
end
75+
end
76+
77+
class Tarjan
78+
attr_accessor :graph, :idx, :stack, :sccs
79+
80+
def initialize(graph)
81+
if graph.class == Graph
82+
@graph = graph
83+
elsif graph.class == Hash
84+
@graph = Graph.new(graph)
85+
end
86+
87+
if graph != nil
88+
@idx = 0
89+
@stack = []
90+
91+
# Runs Tarjan
92+
# Set all node index to None
93+
self.graph.nodes.each do |v|
94+
v.idx = nil
95+
end
96+
97+
@sccs = []
98+
self.graph.nodes.each do |v|
99+
if v.idx == nil
100+
self.strongconnect(v, sccs)
101+
end
102+
end
103+
end
104+
end
105+
106+
def strongconnect(v, sccs)
107+
# Set the depth index for v to the smallest unused index
108+
v.idx = self.idx
109+
v.lowlink = self.idx
110+
self.idx += 1
111+
stack << v
112+
v.on_stack = true
113+
114+
if graph.adjmt[v] != nil
115+
# Consider successors of v
116+
graph.adjmt[v].each do |w|
117+
if w.idx == nil
118+
# Successor w has not yet been visited; recurse on it
119+
self.strongconnect(w, sccs)
120+
v.lowlink = [v.lowlink, w.lowlink].min
121+
elsif w.on_stack
122+
# Successor w is in stack S and hence in the current SCC
123+
# If w is not on stack, then (v, w) is a cross-edge in the DFS tree and must be ignored
124+
# Note: The next line may look odd - but is correct.
125+
# It says w.index not w.lowlink; that is deliberate and from the original paper
126+
v.lowlink = [v.lowlink, w.idx].min
127+
end
128+
end
129+
end
130+
131+
# If v is a root node, pop the stack and generate an SCC
132+
if v.lowlink == v.idx
133+
# start a new strongly connected component
134+
scc = []
135+
while true
136+
w = stack.pop()
137+
w.on_stack = false
138+
scc << w
139+
if w == v
140+
break
141+
end
142+
end
143+
sccs << scc
144+
end
145+
end
146+
end
147+
148+
# Graph from https://en.wikipedia.org/wiki/File:Scc.png
149+
example = {
150+
'A' => ['B'],
151+
'B' => ['C', 'E', 'F'],
152+
'C' => ['D', 'G'],
153+
'D' => ['C', 'H'],
154+
'E' => ['A', 'F'],
155+
'F' => ['G'],
156+
'G' => ['F'],
157+
'H' => ['D', 'G']
158+
}
159+
160+
g = Tarjan.new(example)
161+
print g.sccs.map{|scc| scc.map{|v| v.to_s}}.to_s + "\n"
162+
163+
# Graph from https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm#/media/File:Tarjan%27s_Algorithm_Animation.gif
164+
example = {
165+
'A' => ['E'],
166+
'B' => ['A'],
167+
'C' => ['B', 'D'],
168+
'D' => ['C'],
169+
'E' => ['B'],
170+
'F' => ['B', 'E', 'G'],
171+
'G' => ['F', 'C'],
172+
'H' => ['G', 'H', 'D']
173+
}
174+
g = Tarjan.new(example)
175+
print g.sccs.map{|scc| scc.map{|v| v.to_s}}.to_s + "\n"

src/unique_bsts.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
def unique_bsts(n)
2+
a = Array.new(n+1, 0)
3+
a[0] = a[1] = 1
4+
5+
(2..n).each do |i|
6+
(1..i).each do |j|
7+
a[i] += (a[j-1] * a[i-j])
8+
end
9+
end
10+
11+
return a[n]
12+
end
13+
14+
p unique_bsts(4) # => 14

src/wiggle_subsequence.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# @param {Integer[]} nums
2+
# @return {Integer}
3+
def wiggle_max_length(nums)
4+
return nums.size if nums.size < 2
5+
up = nil
6+
i = 1; res = 0
7+
while i < nums.size
8+
while i < nums.size and (
9+
(up == nil and nums[i] == nums[i-1]) or
10+
(up == true && nums[i] >= nums[i-1]) or
11+
(up == false && nums[i] <= nums[i-1]))
12+
i += 1
13+
end
14+
up = (up == nil and i < nums.size) ? nums[i] > nums[i-1] : !up
15+
res += 1
16+
end
17+
18+
return res
19+
end
20+
21+
p wiggle_max_length([1,17,5,10,13,15,10,5,16,8]) # => 7

0 commit comments

Comments
 (0)