algorithmable 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/algorithmable.gemspec +1 -0
  4. data/lib/algorithmable/cache/imp.rb +19 -0
  5. data/lib/algorithmable/cache/primitive_max_heap.rb +38 -0
  6. data/lib/algorithmable/cache/primitive_min_heap.rb +38 -0
  7. data/lib/algorithmable/cache.rb +15 -0
  8. data/lib/algorithmable/cups/circular_dependencies.rb +27 -0
  9. data/lib/algorithmable/cups/longest_common_subsequence.rb +46 -0
  10. data/lib/algorithmable/cups/merge_two_arrays.rb +31 -0
  11. data/lib/algorithmable/cups/nested_lists_problem.rb +105 -0
  12. data/lib/algorithmable/cups/number_of_occurrences_in_array.rb +49 -0
  13. data/lib/algorithmable/cups/primitives.rb +205 -2
  14. data/lib/algorithmable/cups/root_cube_issue.rb +39 -0
  15. data/lib/algorithmable/cups/stacks_and_queues/stack_sorter.rb +25 -0
  16. data/lib/algorithmable/cups/stacks_and_queues/stack_with_min.rb +23 -0
  17. data/lib/algorithmable/cups/stacks_and_queues/towers_of_hanoi.rb +48 -0
  18. data/lib/algorithmable/cups/stacks_and_queues/triple_stack.rb +52 -0
  19. data/lib/algorithmable/cups/stacks_and_queues/two_stacks_queue.rb +37 -0
  20. data/lib/algorithmable/cups/stacks_and_queues.rb +31 -0
  21. data/lib/algorithmable/cups/stocks.rb +80 -0
  22. data/lib/algorithmable/cups/task_shedule_with_coldtime.rb +16 -0
  23. data/lib/algorithmable/cups/two_sum.rb +59 -0
  24. data/lib/algorithmable/cups.rb +7 -0
  25. data/lib/algorithmable/data_structs/linked_list/base.rb +21 -1
  26. data/lib/algorithmable/data_structs/linked_list/doubly.rb +1 -1
  27. data/lib/algorithmable/data_structs/linked_list/singly.rb +62 -1
  28. data/lib/algorithmable/data_structs/queue.rb +4 -0
  29. data/lib/algorithmable/data_structs/stack.rb +4 -0
  30. data/lib/algorithmable/data_structs/tree/binary.rb +10 -0
  31. data/lib/algorithmable/data_structs/tree/binary_search.rb +206 -0
  32. data/lib/algorithmable/data_structs/tree.rb +13 -0
  33. data/lib/algorithmable/data_structs.rb +6 -0
  34. data/lib/algorithmable/sort/bubble.rb +9 -16
  35. data/lib/algorithmable/sort/insertion.rb +24 -0
  36. data/lib/algorithmable/sort/merge.rb +4 -8
  37. data/lib/algorithmable/sort/quick_sort.rb +35 -0
  38. data/lib/algorithmable/sort/selection.rb +23 -0
  39. data/lib/algorithmable/sort/shell.rb +27 -0
  40. data/lib/algorithmable/sort/shuffle.rb +15 -0
  41. data/lib/algorithmable/sort/utils.rb +66 -0
  42. data/lib/algorithmable/sort.rb +28 -0
  43. data/lib/algorithmable/union_find.rb +51 -0
  44. data/lib/algorithmable/version.rb +1 -1
  45. data/lib/algorithmable.rb +2 -0
  46. data/script/benchmarks/sort.rb +37 -0
  47. metadata +46 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 484ef490b06d5cd0c396fc76651dec47edd406c8
4
- data.tar.gz: ea9ba9dd9e2e6cbc886e3bf1a3022eda64badb21
3
+ metadata.gz: 2819e21aacb2d64cd559ea000b1e91a3e522ed64
4
+ data.tar.gz: 2c44dfea8b1f9552fd28d0de362b7c4617d9772f
5
5
  SHA512:
6
- metadata.gz: d022c89e7953ee18649511d595c126892d7eb8d1c3bedfd21bdcc7804caf2cf592c7ecd8d019a3ec12555728ba17e541170b0b660d7368a879d5ff27961c18bc
7
- data.tar.gz: 4497b73d3190fa9492a8c3966a50c2aa110dafd5e80656218c275d58ece61462859f4598c15a8c8441aa493afef371e09cc9f2b4bd183fb77ba760d98e472e69
6
+ metadata.gz: 7518a1f6a826af9f6a232f77ec85dd4e09d2f93ac1c272d01d3aa20a6ea1c1a25950ba81abcd28ce62c752ed15c599bb3e9de25321f9a1f8e1d0de32240647fc
7
+ data.tar.gz: 912456f9bb48de78827502407b6967c48321f4a8066d1e667f58db0cfca4f4ec16fddbe1408a065e517803f94a982964ed5359019556e890cb7ed2b43ffb1e56
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ Documentation:
3
3
  Style/IndentHash:
4
4
  Enabled: false
5
5
  Metrics/LineLength:
6
- Max: 100
6
+ Max: 130
7
7
  AllCops:
8
8
  Exclude:
9
9
  - doc/**/*
@@ -29,4 +29,5 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'cucumber', '~> 1.3'
30
30
  spec.add_development_dependency 'rspec_junit_formatter', '~> 0'
31
31
  spec.add_development_dependency 'yard', '~> 0.8'
32
+ spec.add_development_dependency 'rbench'
32
33
  end
@@ -0,0 +1,19 @@
1
+ module Algorithmable
2
+ module Cache
3
+ class Imp
4
+ extend Forwardable
5
+
6
+ def_delegators :@heap, :size, :empty?, :[]
7
+
8
+ def initialize(max_size, heap)
9
+ @max_size = max_size
10
+ @heap = heap
11
+ end
12
+
13
+ def []=(key, value)
14
+ @heap.pop if @heap.size >= @max_size
15
+ @heap[key] = value
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ module Algorithmable
2
+ module Cache
3
+ class PrimitiveMaxHeap
4
+ extend Forwardable
5
+
6
+ def_delegators :@index, :size, :empty?
7
+
8
+ def initialize(index = [])
9
+ @storage = {}
10
+ @index = index
11
+ end
12
+
13
+ def []=(key, value)
14
+ swim key
15
+ @storage[key] = value
16
+ end
17
+
18
+ def [](key)
19
+ @storage[key].tap do |value|
20
+ swim key if value
21
+ end
22
+ end
23
+
24
+ def pop
25
+ key = @index.delete @index.last
26
+ @storage.delete key
27
+ end
28
+
29
+ private
30
+
31
+ def swim(key)
32
+ @index.delete(key)
33
+ @index.unshift(key)
34
+ end
35
+ end
36
+ private_constant :PrimitiveMaxHeap
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module Algorithmable
2
+ module Cache
3
+ class PrimitiveMinHeap
4
+ extend Forwardable
5
+
6
+ def_delegators :@index, :size, :empty?
7
+
8
+ def initialize(index = [])
9
+ @storage = {}
10
+ @index = index
11
+ end
12
+
13
+ def []=(key, value)
14
+ sink key
15
+ @storage[key] = value
16
+ end
17
+
18
+ def [](key)
19
+ @storage[key].tap do |value|
20
+ sink key if value
21
+ end
22
+ end
23
+
24
+ def pop
25
+ key = @index.delete @index.last
26
+ @storage.delete key
27
+ end
28
+
29
+ private
30
+
31
+ def sink(key)
32
+ @index.delete(key)
33
+ @index.push(key)
34
+ end
35
+ end
36
+ private_constant :PrimitiveMinHeap
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ module Algorithmable
2
+ module Cache
3
+ autoload :Imp, 'algorithmable/cache/imp'
4
+ autoload :PrimitiveMinHeap, 'algorithmable/cache/primitive_min_heap'
5
+ autoload :PrimitiveMaxHeap, 'algorithmable/cache/primitive_max_heap'
6
+
7
+ def new_lru_cache(size, heap = PrimitiveMaxHeap.new)
8
+ Imp.new size, heap
9
+ end
10
+
11
+ def new_mru_cache(size, heap = PrimitiveMinHeap.new)
12
+ Imp.new size, heap
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module Algorithmable
2
+ module Cups
3
+ module CircularDependencies
4
+ def lib_dependencies(item, dependencies)
5
+ visited = []
6
+ dfs(item, dependencies, visited) do |entry, dep|
7
+ puts "circular dependency: #{entry} <=> #{dep}"
8
+ end
9
+ visited
10
+ end
11
+
12
+ def dfs(item, dependencies, visited, &block)
13
+ next_items = dependencies[item]
14
+ return [] unless next_items
15
+ visited << item
16
+
17
+ next_items.each do |dep|
18
+ if visited.include? dep
19
+ yield item, dep if block_given?
20
+ next
21
+ end
22
+ dfs(dep, dependencies, visited, &block)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,46 @@
1
+ module Algorithmable
2
+ module Cups
3
+ class LongestCommonSubSequence
4
+ #
5
+ # @see https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
6
+ #
7
+ # >> a = "aaaaabbbb34354354345"
8
+ # >> b = "abbb34aaabbbb"
9
+ # >> find(a, b)
10
+ # => "aaaabbbb"
11
+ #
12
+ def find(a, b)
13
+ max_len = Array.new(a.size + 1, 0)
14
+ max_len.map! { Array.new(b.size + 1, 0) }
15
+
16
+ (a.size - 1).downto(0) do |i|
17
+ (b.size - 1).downto(0) do |j|
18
+ if a[i] == b[j]
19
+ max_len[i][j] = 1 + max_len[i + 1][j + 1]
20
+ else
21
+ max_len[i][j] = [max_len[i + 1][j], max_len[i][j + 1]].max
22
+ end
23
+ end
24
+ end
25
+
26
+ res = ''
27
+ i = 0
28
+ j = 0
29
+ while max_len[i][j] != 0 && i < a.size && j < b.size
30
+ if a[i] == b[j]
31
+ res << a[i]
32
+ i += 1
33
+ j += 1
34
+ else
35
+ if max_len[i][j] == max_len[i + 1][j]
36
+ i += 1
37
+ else
38
+ j += 1
39
+ end
40
+ end
41
+ end
42
+ res
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ module Algorithmable
2
+ module Cups
3
+ # Given two lists of numbers in descending order, write a function that returns a single list sorted in the same order.
4
+ # E.g.
5
+ # list1: 4, 2, 1
6
+ # list2: 7, 6, 5, 3
7
+ # Result list should be: 7,6,5,4,3,2,1
8
+
9
+ # right = [4, 2, 1]
10
+ # left = [7, 6, 5, 3]
11
+ #
12
+ # l1 = [1]
13
+ # l2 = []
14
+
15
+ def merge_arrays(left, right)
16
+ sorted = []
17
+
18
+ while !left.empty? && !right.empty?
19
+ if left[0] >= right[0]
20
+ sorted.push(left.shift)
21
+ else
22
+ sorted.push(right.shift)
23
+ end
24
+ end
25
+
26
+ sorted += left if right.empty?
27
+ sorted += right if left.empty?
28
+ sorted # [1]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,105 @@
1
+ module Algorithmable
2
+ module Cups
3
+ module NestedListsProblem
4
+ # /**
5
+ # * Given a nested list of integers, returns the sum of all integers in the list weighted by their depth
6
+ # * For example, given the list {{1,1},2,{1,1}} the function should return 10 (four 1's at depth 2, one 2 at depth 1)
7
+ # * Given the list {1,{4,{6}}} the function should return 27 (one 1 at depth 1, one 4 at depth 2, and one 6 at depth 3)
8
+ # */
9
+ #
10
+ # public int depthSum (List<NestedInteger> input)
11
+ # {
12
+ # // ur implementation here
13
+ # }
14
+ #
15
+ # **
16
+ # * This is the interface that represents nested lists.
17
+ # * You should not implement it, or speculate about its implementation.
18
+ # */
19
+ # public interface NestedInteger
20
+ # {
21
+ # /** @return true if this NestedInteger holds a single integer, rather than a nested list */
22
+ # boolean isInteger();
23
+ #
24
+ # /** @return the single integer that this NestedInteger holds, if it holds a single integer
25
+ # * Return null if this NestedInteger holds a nested list
26
+ # */
27
+ # Integer getInteger();
28
+ #
29
+ # /** @return the nested list that this NestedInteger holds, if it holds a nested list
30
+ # * Return null if this NestedInteger holds a single integer
31
+ # */
32
+ # List<NestedInteger> getList();
33
+ # }
34
+
35
+ def make_list(collection, level = 0, buffer = new_nested_list)
36
+ collection.each do |entry|
37
+ if entry.is_a? Array
38
+ buffer << make_list(entry, level + 1)
39
+ else
40
+ buffer << entry
41
+ end
42
+ end
43
+ buffer
44
+ end
45
+
46
+ def new_nested_list(collection = [])
47
+ NestedListImp.new collection
48
+ end
49
+
50
+ def solve_puzzle(nested_list)
51
+ PuzzleSolver.find_sum_of_nodes_in nested_list
52
+ end
53
+
54
+ class NestedListImp
55
+ attr_accessor :value
56
+
57
+ def initialize(collection = [])
58
+ @collection = collection
59
+ end
60
+
61
+ def integer?
62
+ @collection.is_a? Fixnum
63
+ end
64
+
65
+ def <<(other)
66
+ @collection << other
67
+ end
68
+
69
+ def value
70
+ @collection
71
+ end
72
+
73
+ def each(&block)
74
+ @collection.each(&block)
75
+ end
76
+ end
77
+
78
+ private_constant :NestedListImp
79
+
80
+ class PuzzleSolver
81
+ def self.find_sum_of_nodes_in(nested_list)
82
+ new.find_sum_of_nodes_in nested_list
83
+ end
84
+
85
+ def find_sum_of_nodes_in(nested_list)
86
+ recursive_sum nested_list, 1
87
+ end
88
+
89
+ def recursive_sum(list, at_level)
90
+ sum = 0
91
+ list.each do |entry|
92
+ if entry.integer?
93
+ sum += entry * at_level
94
+ else
95
+ sum += recursive_sum entry, at_level + 1
96
+ end
97
+ end
98
+ sum
99
+ end
100
+ end
101
+
102
+ private_constant :PuzzleSolver
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,49 @@
1
+ module Algorithmable
2
+ module Cups
3
+ module NumberOfOccurrencesInArray
4
+ include Algorithmable::Searches
5
+
6
+ def linear_solve(collection, target)
7
+ result = Hash.new 0
8
+ collection.each do |item|
9
+ result[item] += 1
10
+ end
11
+ result[target]
12
+ end
13
+
14
+ def logarithmic(collection, target)
15
+ i = find_first_one collection, 0, collection.size - 1, target
16
+ j = find_last_one collection, i, collection.size - 1, target
17
+ j - i + 1
18
+ end
19
+
20
+ def find_first_one(collection, low, high, target)
21
+ # if(high >= low)
22
+ # {
23
+ # int mid = (low + high)/2; /*low + (high - low)/2;*/
24
+ # if( ( mid == 0 || x > arr[mid-1]) && arr[mid] == x)
25
+ # return mid;
26
+ # else if(x > arr[mid])
27
+ # return first(arr, (mid + 1), high, x, n);
28
+ # else
29
+ # return first(arr, low, (mid -1), x, n);
30
+ # }
31
+ # return -1
32
+ end
33
+
34
+ def find_last_one(collection, low, high, target)
35
+ # if(high >= low)
36
+ # {
37
+ # int mid = (low + high)/2; /*low + (high - low)/2;*/
38
+ # if( ( mid == n-1 || x < arr[mid+1]) && arr[mid] == x )
39
+ # return mid;
40
+ # else if(x < arr[mid])
41
+ # return last(arr, low, (mid -1), x, n);
42
+ # else
43
+ # return last(arr, (mid + 1), high, x, n);
44
+ # }
45
+ # return -1;
46
+ end
47
+ end
48
+ end
49
+ end
@@ -20,7 +20,7 @@ module Algorithmable
20
20
  j = index + 1
21
21
  chars[new_length - j] = char
22
22
  end
23
- new_length = new_length - replacement.length
23
+ new_length -= replacement.length
24
24
  else
25
25
  new_length -= 1
26
26
  chars[new_length] = string[i]
@@ -71,7 +71,7 @@ module Algorithmable
71
71
  end
72
72
 
73
73
  def find_cycled_node(root)
74
- return unless root.next or root.next.next
74
+ return unless root.next || root.next.next
75
75
  slow = root
76
76
  fast = root
77
77
 
@@ -93,6 +93,209 @@ module Algorithmable
93
93
  # at this point return value is a node which is tail pointing to.
94
94
  fast
95
95
  end
96
+
97
+ def ransom_note(note, magazine)
98
+ ascii_table = Hash.new 0
99
+ source = magazine.chars
100
+
101
+ source.each do |char|
102
+ ascii_table[char] += 1
103
+ end
104
+
105
+ note.chars.each do |char|
106
+ return false unless ascii_table[char].nonzero?
107
+ ascii_table[char] -= 1
108
+ end
109
+
110
+ true
111
+ end
112
+
113
+ def anagrams?(string, other_string)
114
+ return false unless string.size == other_string.size
115
+ registry = Hash.new 0
116
+ string.each_char do |char|
117
+ registry[char] += 1
118
+ end
119
+ other_string.chars.none? do |char|
120
+ (registry[char] -= 1) < 0
121
+ end
122
+ end
123
+
124
+ def parse_string_with_escapes(string)
125
+ app_state = {
126
+ chunk_id: 0,
127
+ escaping: false,
128
+ prev_char: nil,
129
+ chunks: Hash.new { |h, k| h[k] = [] }
130
+ }
131
+
132
+ string.each_char do |char|
133
+ parse_char char, app_state
134
+ end
135
+
136
+ app_state[:chunks].values
137
+ end
138
+
139
+ def parse_char(char, state)
140
+ chunk_id = state[:chunk_id]
141
+ case char
142
+ when /[\(\{\[\)\}\]]/
143
+ state[:escaping] = char != state[:prev_char]
144
+ state[:chunks][chunk_id] << char unless state[:escaping]
145
+ else
146
+ if state[:escaping]
147
+ chunk_id = state[:chunk_id] += 1
148
+ state[:escaping] = false
149
+ end
150
+ state[:chunks][chunk_id] << char
151
+ end
152
+ state[:prev_char] = char
153
+ end
154
+
155
+ def remove_duplicates_from_list(list)
156
+ map = {}
157
+ prev = nil
158
+ node = list.front
159
+
160
+ while node
161
+ if map[node.item]
162
+ prev.next = node.next
163
+ else
164
+ map[node.item] = true
165
+ prev = node
166
+ end
167
+ node = node.next
168
+ end
169
+ end
170
+
171
+ def nth_to_last_in_list(list, nth = 1)
172
+ return if list.nil? || list.empty?
173
+ node1 = list.front
174
+ node2 = list.front
175
+
176
+ nth.downto(nth).each do |_i|
177
+ if node1
178
+
179
+ end
180
+ end
181
+ end
182
+
183
+ #
184
+ # int maxDiff(int arr[], int arr_size)
185
+ # {
186
+ # int max_diff = arr[1] - arr[0];
187
+ # int i, j;
188
+ # for(i = 0; i < arr_size; i++)
189
+ # {
190
+ # for(j = i+1; j < arr_size; j++)
191
+ # {
192
+ # if(arr[j] - arr[i] > max_diff)
193
+ # max_diff = arr[j] - arr[i];
194
+ # }
195
+ # }
196
+ # return max_diff;
197
+ # }
198
+ #
199
+ # getBestTime(int stocks[], int sz, int &buy, int &sell) {
200
+ # int min = 0;
201
+ # int maxDiff = 0;
202
+ # buy = sell = 0;
203
+ # for (int i = 0; i < sz; i++) {
204
+ # if (stocks[i] < stocks[min])
205
+ # min = i;
206
+ # int diff = stocks[i] - stocks[min];
207
+ # if (diff > maxDiff) {
208
+ # buy = min;
209
+ # sell = i;
210
+ # maxDiff = diff;
211
+ # }
212
+ # }
213
+ # }
214
+ #
215
+
216
+ def sort_linked_list(node)
217
+ return unless node || node.empty?
218
+ swapped = false
219
+ prev = nil
220
+
221
+ begin
222
+ swapped = false
223
+ current = node
224
+
225
+ until current.next == prev
226
+ if current.item > current.next.item
227
+ swap_nodes current, current.next
228
+ swapped = true
229
+ end
230
+ current = current.next
231
+ end
232
+
233
+ prev = current
234
+ end while swapped
235
+ end
236
+
237
+ def swap_nodes(node1, node2)
238
+ tmp = node1.item
239
+ node1.item = node2.item
240
+ node2.item = tmp
241
+ end
242
+
243
+ # Write a program that gives count of common characters presented in an array of strings..(or array of character arrays)
244
+ #
245
+ # For eg.. for the following input strings..
246
+ #
247
+ # aghkafgklt
248
+ # dfghako
249
+ # qwemnaarkf
250
+ #
251
+ # The output should be 3. because the characters a, f and k are present in all 3 strings.
252
+ #
253
+ # Note: The input strings contains only lower case alphabets
254
+ def find_common_chars_in_words(collection)
255
+ map = Hash.new 0
256
+
257
+ collection.each_with_index do |word, index|
258
+ word.chars.each do |char|
259
+ map[char] += 1 if map[char] == index
260
+ end
261
+ end
262
+
263
+ map.select do |key, value|
264
+ { key => value } if value == collection.size
265
+ end
266
+ end
267
+
268
+ # /* This class will be given a list of words (such as might be tokenized
269
+ # * from a paragraph of text), and will provide a method that takes two
270
+ # * words and returns the shortest distance (in words) between those two
271
+ # * words in the provided text.
272
+ # * Example:
273
+ # * WordDistanceFinder finder = new WordDistanceFinder(Arrays.asList("the", "quick", "brown", "fox", "quick"));
274
+ # * assert(finder.distance("fox","the") == 3);
275
+ # * assert(finder.distance("quick", "fox") == 1);
276
+ # * /
277
+
278
+ def find_distance_between_words(dictionary, from, to)
279
+ return 0 if from == to
280
+
281
+ dict_size = dictionary.size
282
+ distance = -1
283
+
284
+ dictionary.each_with_index do |word, index|
285
+ next unless [from, to].include? word
286
+ temp = word == from
287
+ to = temp ? to : from
288
+ distance += 1
289
+
290
+ i = index
291
+ while i < dict_size - 1 && dictionary[i] != to
292
+ i += 1
293
+ distance += 1
294
+ return distance if dictionary[i] == to
295
+ end
296
+ end
297
+ distance
298
+ end
96
299
  end
97
300
  end
98
301
  end