algorithmable 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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