algorithmable 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/algorithmable.gemspec +1 -0
- data/lib/algorithmable/cache/imp.rb +19 -0
- data/lib/algorithmable/cache/primitive_max_heap.rb +38 -0
- data/lib/algorithmable/cache/primitive_min_heap.rb +38 -0
- data/lib/algorithmable/cache.rb +15 -0
- data/lib/algorithmable/cups/circular_dependencies.rb +27 -0
- data/lib/algorithmable/cups/longest_common_subsequence.rb +46 -0
- data/lib/algorithmable/cups/merge_two_arrays.rb +31 -0
- data/lib/algorithmable/cups/nested_lists_problem.rb +105 -0
- data/lib/algorithmable/cups/number_of_occurrences_in_array.rb +49 -0
- data/lib/algorithmable/cups/primitives.rb +205 -2
- data/lib/algorithmable/cups/root_cube_issue.rb +39 -0
- data/lib/algorithmable/cups/stacks_and_queues/stack_sorter.rb +25 -0
- data/lib/algorithmable/cups/stacks_and_queues/stack_with_min.rb +23 -0
- data/lib/algorithmable/cups/stacks_and_queues/towers_of_hanoi.rb +48 -0
- data/lib/algorithmable/cups/stacks_and_queues/triple_stack.rb +52 -0
- data/lib/algorithmable/cups/stacks_and_queues/two_stacks_queue.rb +37 -0
- data/lib/algorithmable/cups/stacks_and_queues.rb +31 -0
- data/lib/algorithmable/cups/stocks.rb +80 -0
- data/lib/algorithmable/cups/task_shedule_with_coldtime.rb +16 -0
- data/lib/algorithmable/cups/two_sum.rb +59 -0
- data/lib/algorithmable/cups.rb +7 -0
- data/lib/algorithmable/data_structs/linked_list/base.rb +21 -1
- data/lib/algorithmable/data_structs/linked_list/doubly.rb +1 -1
- data/lib/algorithmable/data_structs/linked_list/singly.rb +62 -1
- data/lib/algorithmable/data_structs/queue.rb +4 -0
- data/lib/algorithmable/data_structs/stack.rb +4 -0
- data/lib/algorithmable/data_structs/tree/binary.rb +10 -0
- data/lib/algorithmable/data_structs/tree/binary_search.rb +206 -0
- data/lib/algorithmable/data_structs/tree.rb +13 -0
- data/lib/algorithmable/data_structs.rb +6 -0
- data/lib/algorithmable/sort/bubble.rb +9 -16
- data/lib/algorithmable/sort/insertion.rb +24 -0
- data/lib/algorithmable/sort/merge.rb +4 -8
- data/lib/algorithmable/sort/quick_sort.rb +35 -0
- data/lib/algorithmable/sort/selection.rb +23 -0
- data/lib/algorithmable/sort/shell.rb +27 -0
- data/lib/algorithmable/sort/shuffle.rb +15 -0
- data/lib/algorithmable/sort/utils.rb +66 -0
- data/lib/algorithmable/sort.rb +28 -0
- data/lib/algorithmable/union_find.rb +51 -0
- data/lib/algorithmable/version.rb +1 -1
- data/lib/algorithmable.rb +2 -0
- data/script/benchmarks/sort.rb +37 -0
- metadata +46 -2
@@ -0,0 +1,39 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module RootCubeIssue
|
4
|
+
# What is the fastest way to compute cube root?
|
5
|
+
|
6
|
+
ACCURACY = 0.0001
|
7
|
+
|
8
|
+
def self.binary_search(num, accuracy = ACCURACY)
|
9
|
+
low = 0
|
10
|
+
high = num
|
11
|
+
mid = 0
|
12
|
+
|
13
|
+
loop do
|
14
|
+
mid = (low + high) / 2.0
|
15
|
+
cube = mid * mid * mid
|
16
|
+
break if (cube - num).abs <= accuracy
|
17
|
+
if cube > num
|
18
|
+
high = mid
|
19
|
+
else
|
20
|
+
low = mid
|
21
|
+
end
|
22
|
+
end
|
23
|
+
mid
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.newton_approximation(num, accuracy = ACCURACY)
|
27
|
+
x = 1
|
28
|
+
n = 10
|
29
|
+
loop do
|
30
|
+
0.upto(n).each do
|
31
|
+
x = (2 * x + num / (x * x)) / 3.0
|
32
|
+
end
|
33
|
+
break if ((x * x * x) - num).abs < accuracy
|
34
|
+
end
|
35
|
+
x
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module StacksAndQueues
|
4
|
+
class StackSorter
|
5
|
+
include Algorithmable::DataStructs
|
6
|
+
|
7
|
+
def self.sort(stack)
|
8
|
+
new.sort(stack)
|
9
|
+
end
|
10
|
+
|
11
|
+
def sort(stack)
|
12
|
+
local_stack = new_lifo_queue
|
13
|
+
until stack.empty?
|
14
|
+
temp = stack.pop
|
15
|
+
while !local_stack.empty? && local_stack.peek < temp
|
16
|
+
stack.push local_stack.pop
|
17
|
+
end
|
18
|
+
local_stack.push temp
|
19
|
+
end
|
20
|
+
local_stack
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module StacksAndQueues
|
4
|
+
class StackWithMin < Algorithmable::DataStructs::Stack
|
5
|
+
MAX_INT = 2**32
|
6
|
+
NodeWithMin = Struct.new(:item, :minimum)
|
7
|
+
|
8
|
+
private_constant :NodeWithMin
|
9
|
+
|
10
|
+
def push(item)
|
11
|
+
new_min = [item, min].min
|
12
|
+
node = NodeWithMin.new item, new_min
|
13
|
+
super node
|
14
|
+
end
|
15
|
+
|
16
|
+
def min
|
17
|
+
return MAX_INT if empty?
|
18
|
+
peek.min
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module StacksAndQueues
|
4
|
+
module TowersOfHanoi
|
5
|
+
class Tower
|
6
|
+
include Algorithmable::DataStructs
|
7
|
+
|
8
|
+
attr_reader :index
|
9
|
+
|
10
|
+
def initialize(index)
|
11
|
+
@disks = new_lifo_queue
|
12
|
+
@index = index
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(disk)
|
16
|
+
fail "Error placing disk #{disk} on #{@disks.peek}." if !@disks.empty? && @disks.peek <= disk
|
17
|
+
@disks.push disk
|
18
|
+
end
|
19
|
+
|
20
|
+
def move_top_to_tower(other_tower)
|
21
|
+
top = @disks.pop
|
22
|
+
debug "Moving disk ##{top} from tower #{index} to #{other_tower.index}."
|
23
|
+
other_tower.add top
|
24
|
+
end
|
25
|
+
|
26
|
+
def move_disks(amount, destination, buffer)
|
27
|
+
return unless amount > 0
|
28
|
+
move_disks amount - 1, buffer, destination
|
29
|
+
move_top_to_tower destination
|
30
|
+
buffer.move_disks amount - 1, destination, self
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
"#<Tower ##{index} #{@disks}>"
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_a
|
38
|
+
@disks.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
def debug(message)
|
42
|
+
puts message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module StacksAndQueues
|
4
|
+
class TripleStack
|
5
|
+
MAX_INT = 2**32
|
6
|
+
|
7
|
+
def initialize(size)
|
8
|
+
@size = size + 1
|
9
|
+
@pointers = [0, 0, 0]
|
10
|
+
@array = Array.new (@size * 3)
|
11
|
+
0.upto(2).each do |index|
|
12
|
+
@array[@size * index] = MAX_INT
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def push(stack_num, item)
|
17
|
+
pointer = get_stack_pointer(stack_num) + 1
|
18
|
+
@pointers[stack_num] += 1
|
19
|
+
@array[pointer] = item
|
20
|
+
item
|
21
|
+
end
|
22
|
+
|
23
|
+
def pop(stack_num)
|
24
|
+
pointer = get_stack_pointer(stack_num)
|
25
|
+
value = @array[pointer]
|
26
|
+
@array[pointer] = nil
|
27
|
+
@pointers[stack_num] -= 1
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def peek(stack_num)
|
32
|
+
pointer = get_stack_pointer(stack_num)
|
33
|
+
@array[pointer]
|
34
|
+
end
|
35
|
+
|
36
|
+
def empty?(stack_num)
|
37
|
+
@pointers[stack_num].zero?
|
38
|
+
end
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
"#<Stack @pointers=#{@pointers} @stacks=#{@array}>"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def get_stack_pointer(stack_num)
|
47
|
+
@size * stack_num + @pointers[stack_num]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module StacksAndQueues
|
4
|
+
class TwoStacksQueue
|
5
|
+
include Algorithmable::DataStructs
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@stack_a = new_lifo_queue
|
9
|
+
@stack_b = new_lifo_queue
|
10
|
+
end
|
11
|
+
|
12
|
+
def size
|
13
|
+
@stack_a.size + @stack_b.size
|
14
|
+
end
|
15
|
+
|
16
|
+
def enqueue(item)
|
17
|
+
unless @stack_b.empty?
|
18
|
+
@stack_a.push @stack_b.pop until @stack_b.empty?
|
19
|
+
end
|
20
|
+
@stack_a.push(item)
|
21
|
+
end
|
22
|
+
|
23
|
+
def dequeue
|
24
|
+
return @stack_b.dequeue unless @stack_b.empty?
|
25
|
+
@stack_b.push @stack_a.pop until @stack_a.empty?
|
26
|
+
@stack_b.pop
|
27
|
+
end
|
28
|
+
|
29
|
+
def peek
|
30
|
+
return @stack_b.peek unless @stack_b.empty?
|
31
|
+
@stack_b.push @stack_a.pop until @stack_a.empty?
|
32
|
+
@stack_b.peek
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module StacksAndQueues
|
4
|
+
autoload :TwoStacksQueue, 'algorithmable/cups/stacks_and_queues/two_stacks_queue'
|
5
|
+
autoload :StackWithMin, 'algorithmable/cups/stacks_and_queues/stack_with_min'
|
6
|
+
autoload :TripleStack, 'algorithmable/cups/stacks_and_queues/triple_stack'
|
7
|
+
autoload :StackSorter, 'algorithmable/cups/stacks_and_queues/stack_sorter'
|
8
|
+
autoload :TowersOfHanoi, 'algorithmable/cups/stacks_and_queues/towers_of_hanoi'
|
9
|
+
|
10
|
+
def new_triple_stack(size)
|
11
|
+
TripleStack.new size
|
12
|
+
end
|
13
|
+
|
14
|
+
def new_stack_with_min
|
15
|
+
StackWithMin.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_two_stacks_queue
|
19
|
+
TwoStacksQueue.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def sort_stack(stack)
|
23
|
+
StackSorter.sort stack
|
24
|
+
end
|
25
|
+
|
26
|
+
def new_tower_of_hanoi(index)
|
27
|
+
TowersOfHanoi::Tower.new index
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module Stocks
|
4
|
+
# If you were only permitted to buy one share of the stock and sell one share of the stock,
|
5
|
+
# design an algorithm to find the best times to buy and sell.
|
6
|
+
def get_best_time(stocks)
|
7
|
+
min = 0
|
8
|
+
max_diff = 0
|
9
|
+
buy = 0
|
10
|
+
sell = 0
|
11
|
+
0.upto(stocks.size - 1).each do |i|
|
12
|
+
min = i if stocks[i] < stocks[min]
|
13
|
+
diff = stocks[i] - stocks[min]
|
14
|
+
next unless diff > max_diff
|
15
|
+
buy = min
|
16
|
+
sell = i
|
17
|
+
max_diff = diff
|
18
|
+
end
|
19
|
+
{ buy_at: buy, sell_at: sell, max_profit: max_diff }
|
20
|
+
end
|
21
|
+
|
22
|
+
# another way
|
23
|
+
#
|
24
|
+
def find_max_profit(arr)
|
25
|
+
max_diff = arr[1] - arr[0]
|
26
|
+
0.upto(arr.size).each do |i|
|
27
|
+
(i + 1).upto(arr.size - 1).each do |j|
|
28
|
+
max_diff = arr[j] - arr[i] if arr[j] - arr[i] > max_diff
|
29
|
+
end
|
30
|
+
end
|
31
|
+
max_diff
|
32
|
+
end
|
33
|
+
|
34
|
+
# The cost of a stock on each current_day is given in an array, find the max profit that you can make by
|
35
|
+
# buying and selling in those days.
|
36
|
+
# For example, if the given array is {100, 180, 260, 310, 40, 535, 695},
|
37
|
+
# the maximum profit can earned by buying on current_day 0, selling on current_day 3.
|
38
|
+
# Again buy on current_day 4 and sell on current_day 6. If the given array of prices is sorted in decreasing order,
|
39
|
+
# then profit cannot be earned at all.
|
40
|
+
|
41
|
+
# If we are allowed to buy and sell only once, then we can use following algorithm.
|
42
|
+
# Maximum difference between two elements. Here we are allowed to buy and sell multiple times.
|
43
|
+
#
|
44
|
+
# Following is algorithm for this problem.
|
45
|
+
# 1. Find the local minima and store it as starting index. If not exists, return.
|
46
|
+
# 2. Find the local maxima. and store it as ending index. If we reach the end, set the end as ending index.
|
47
|
+
# 3. Update the solution (Increment count of buy sell pairs)
|
48
|
+
# 4. Repeat the above steps if end is not reached.
|
49
|
+
#
|
50
|
+
# http://www.geeksforgeeks.org/stock-buy-sell/
|
51
|
+
def ruby_buy_and_sell_stocks(stocks)
|
52
|
+
total_days = stocks.size - 1
|
53
|
+
current_day = 0
|
54
|
+
series_count = 0
|
55
|
+
series = []
|
56
|
+
|
57
|
+
while current_day < total_days
|
58
|
+
while current_day <= total_days && stocks[current_day + 1] <= stocks[current_day]
|
59
|
+
current_day += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
return series if current_day == total_days
|
63
|
+
|
64
|
+
series[series_count] = { buy: 0, sell: 0 }
|
65
|
+
series[series_count][:buy] = current_day
|
66
|
+
current_day += 1
|
67
|
+
|
68
|
+
while current_day <= total_days && stocks[current_day] >= stocks[current_day - 1]
|
69
|
+
current_day += 1
|
70
|
+
end
|
71
|
+
|
72
|
+
series[series_count][:sell] = current_day - 1
|
73
|
+
series_count += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
series
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
class TaskScheduleWithColdTime
|
4
|
+
# Task schedule: given a sequence of task like A B C(means 3 different tasks), and a coldtime, which means you need to wait for that much time to start next [same] task. Now----
|
5
|
+
#
|
6
|
+
# Input: string, n
|
7
|
+
# Output: the best task-finishing sequence.
|
8
|
+
#
|
9
|
+
# eg. input: AAABBB, 2
|
10
|
+
# Output: AB_AB_AB
|
11
|
+
# ( "_" represents do nothing and wait)
|
12
|
+
def solve(sequence_of_tasks)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Algorithmable
|
2
|
+
module Cups
|
3
|
+
module TwoSum
|
4
|
+
# Given an array of integers, find two numbers such that they add up to a specific target number.
|
5
|
+
#
|
6
|
+
# The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
|
7
|
+
#
|
8
|
+
# For example:
|
9
|
+
#
|
10
|
+
# Input: numbers={2, 7, 11, 15}, target=9
|
11
|
+
# Output: index1=1, index2=2
|
12
|
+
class Quadratic
|
13
|
+
def solve(collection, target)
|
14
|
+
result = {}
|
15
|
+
collection.each_with_index do |_, index|
|
16
|
+
j = index + 1
|
17
|
+
while j < collection.size
|
18
|
+
if collection[index] + collection[j] == target
|
19
|
+
result[index] = collection[index]
|
20
|
+
result[j] = collection[j]
|
21
|
+
end
|
22
|
+
j += 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# public class Solution {
|
30
|
+
# public int[] twoSum(int[] numbers, int target) {
|
31
|
+
# HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
|
32
|
+
# int[] result = new int[2];
|
33
|
+
#
|
34
|
+
# for (int i = 0; i < numbers.length; i++) {
|
35
|
+
# if (map.containsKey(numbers[i])) {
|
36
|
+
# int index = map.get(numbers[i]);
|
37
|
+
# result[0] = index+1 ;
|
38
|
+
# result[1] = i+1;
|
39
|
+
# break;
|
40
|
+
# } else {
|
41
|
+
# map.put(target - numbers[i], i);
|
42
|
+
# }
|
43
|
+
# }
|
44
|
+
#
|
45
|
+
# return result;
|
46
|
+
# }
|
47
|
+
# }
|
48
|
+
|
49
|
+
class Logarithmic
|
50
|
+
def solve(collection, target)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def new_quadratic_solution
|
55
|
+
Quadratic.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/algorithmable/cups.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module Algorithmable
|
2
2
|
module Cups
|
3
3
|
autoload :Primitives, 'algorithmable/cups/primitives'
|
4
|
+
autoload :Stocks, 'algorithmable/cups/stocks'
|
5
|
+
autoload :StacksAndQueues, 'algorithmable/cups/stacks_and_queues'
|
6
|
+
autoload :NestedListsProblem, 'algorithmable/cups/nested_lists_problem'
|
7
|
+
autoload :TwoSum, 'algorithmable/cups/two_sum'
|
8
|
+
autoload :NumberOfOccurrencesInArray, 'algorithmable/cups/stacks_and_queues/number_of_occurrences_in_array'
|
9
|
+
autoload :LongestCommonSubSequence, 'algorithmable/cups/longest_common_subsequence'
|
10
|
+
autoload :RootCubeIssue, 'algorithmable/cups/root_cube_issue'
|
4
11
|
end
|
5
12
|
end
|
@@ -53,7 +53,15 @@ module Algorithmable
|
|
53
53
|
fail NotImplementedError
|
54
54
|
end
|
55
55
|
|
56
|
-
def reverse
|
56
|
+
def reverse!
|
57
|
+
fail NotImplementedError
|
58
|
+
end
|
59
|
+
|
60
|
+
def sort!
|
61
|
+
fail NotImplementedError
|
62
|
+
end
|
63
|
+
|
64
|
+
def merge!(_other_list)
|
57
65
|
fail NotImplementedError
|
58
66
|
end
|
59
67
|
|
@@ -61,6 +69,18 @@ module Algorithmable
|
|
61
69
|
fail NotImplementedError
|
62
70
|
end
|
63
71
|
|
72
|
+
def find_intersect(_other)
|
73
|
+
fail NotImplementedError
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
to_a.join('->')
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_a
|
81
|
+
each.map(&:item)
|
82
|
+
end
|
83
|
+
|
64
84
|
private
|
65
85
|
|
66
86
|
def search(item)
|