Skip to content

Commit 20fcf3c

Browse files
committed
Merge branch 'master' of github.com:sagivo/algorithms
2 parents 2aed7d9 + 2699295 commit 20fcf3c

File tree

4 files changed

+189
-15
lines changed

4 files changed

+189
-15
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ This is my way of saying - change your interview style. There are lots of smart
5050
| Suggest index of a number in an array | [click](https://github.com/sagivo/algorithms/blob/master/src/sugget_index_in_array.rb) |
5151
| [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) |
5252
| [Insertion Sort](https://en.wikipedia.org/wiki/Insertion_sort) | [click](https://github.com/sagivo/algorithms/blob/master/src/insertion_sort.rb) |
53+
| [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) |
5354

5455

5556
# How?

src/count_and_say.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
# @return {String}
33
def count_and_say(n)
44
return "1" unless n > 1
5-
a = "1";
5+
a = "1"
66
(n-1).times do
77
t = ''; last = nil; count = 0
8-
a.chars.each_with_index do |c,i|
8+
a.chars.each do |c|
99
if c == last or last.nil?
10-
count+=1
10+
count +=1
1111
else
12-
t+= (count.to_s + last);
12+
t += count.to_s + last
1313
count = 1
1414
end
1515
last = c
1616
end
17-
t += (count.to_s + last) if count > 0
18-
a=t
17+
t += count.to_s + last if count > 0
18+
a = t
1919
end
2020
return a
2121
end

src/powerset.rb

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
#powerset - subset of set
2-
def powerset arr
3-
a = [[]]
4-
for num in arr
5-
size_a = a.size; j = 0;
6-
while j < size_a
7-
a << (a[j] + [num])
8-
j+=1
2+
def powerset(arr)
3+
result = [[]]
4+
arr.each do |num|
5+
(0...arr.size).each do |j|
6+
result << result[j] + [num]
97
end
108
end
11-
a
9+
result
1210
end
1311

14-
p powerset [1,2,3] #[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
12+
p powerset [1,2,3] #[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

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"

0 commit comments

Comments
 (0)