kata-algorithms 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e796ad4d1ba7ced44cbcb08c5d8e76609d0ebec8
4
- data.tar.gz: 3450d795d0db2cc5d0a80256b75c9bbe987c68b3
3
+ metadata.gz: 11473fc1abab0c3f6e5347346160f5e3879f148a
4
+ data.tar.gz: cc880d1f93c92b66dc1ed15726c62e11a8349c29
5
5
  SHA512:
6
- metadata.gz: cc7265967142ef4aea31e8375e394a048161bd497d03c4be830b61fff9305eb3fca31e31779d87d35292f6412be073f06a03c934c705e337a73ca584a6b0b366
7
- data.tar.gz: 4972a622b67c9e11a9a6a9e4afead3e80e4522ce04eb1e8cbd57c5a7823b029976c75d593fb5c2dbcfc3cf6f8fedba1c0333b8c8548f2c27d31772082d704efe
6
+ metadata.gz: dedc8a276befadff2ac0bc9bb44733eb50df0c5f9d10360f5a161a4dc1d402813ed23be1e79407a9d4bdfc83ba48f296690d6b7312e89c26d786a7deba24eeba
7
+ data.tar.gz: 6c7797e1ec4d940e6a0da4c545173f0dc71c682987040438cb839c200079324365ae06e1dcf81246f2345a0dc1a1cb19e872c77b7883b8c8dce1754df974fba4
data/CHANGELOG CHANGED
@@ -1 +1,3 @@
1
+ v0.3.0 Added the sum of three algorithms
2
+
1
3
  v0.2.0 Added algorithms for calculating GCD
@@ -16,8 +16,11 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ["lib", File.join('lib', 'kata'),
20
+ File.join('lib', 'kata', 'algorithms'),
21
+ File.join('lib', 'kata', 'algorithms', 'sum_of_three')]
20
22
 
23
+ spec.add_dependency 'json'
21
24
  spec.add_development_dependency "bundler", "~> 1.3"
22
25
  spec.add_development_dependency "rspec"
23
26
  end
@@ -1,4 +1,5 @@
1
1
  require "kata/algorithms/version"
2
+ require "kata/algorithms/all"
2
3
 
3
4
  module Kata
4
5
  module Algorithms
@@ -0,0 +1,4 @@
1
+ require 'sorting'
2
+ require 'sum_of_three/sum_of_three'
3
+ require 'sum_of_three/sum_of_three_hash'
4
+ require 'sum_of_three/sum_of_three_sort'
@@ -0,0 +1,24 @@
1
+ module Kata
2
+ module Algorithms
3
+ module Sorting
4
+ # @param array_to_sort [Array{Integer}]
5
+ # @return the same array sorted using insertion sort
6
+ #
7
+ def self.insertion_sort(array_to_sort)
8
+ return array_to_sort if array_to_sort.nil? || array_to_sort.size == 0 || array_to_sort.size == 1
9
+ i = 1
10
+ while i < array_to_sort.size
11
+ value = array_to_sort[i]
12
+ j = i - 1
13
+ while j >= 0 && array_to_sort[j] >= value
14
+ array_to_sort[j + 1] = array_to_sort[j]
15
+ j -= 1
16
+ end
17
+ array_to_sort[j+1] = value
18
+ i += 1
19
+ end
20
+ array_to_sort
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ SUM of 3
2
+ ========
3
+
4
+ Problem
5
+ -------
6
+ Finding a 3 Integer Subset in Ruby.
7
+ Write a function (with tests) that takes an unsorted integer array, and returns a three element subset whose sum is zero.
8
+
9
+ Example result:
10
+
11
+ [3, -2, 1, -1, 0, -2] => [1, -1, 0] or [3, -2, -1]
12
+
13
+ Solution
14
+ --------
15
+
16
+ Two implementations are provided.
17
+
18
+ 1. Uses a hash to store the positions of the integers
19
+ 2. Sorts the input array first
20
+
21
+ Details and documentation can be found inside the corresponding ruby files that have the implementations
22
+
23
+ Test
24
+ ----
25
+
26
+ ```
27
+ bundle exec rspec
28
+ ```
29
+
30
+ You can also edit the file `spec/example_data/examples.json` to set expectations
@@ -0,0 +1,9 @@
1
+ module Kata
2
+ module Algorithms
3
+ class SumOfThree < Struct.new(:array_of_integers)
4
+ def find_three
5
+ raise NotImplementedError.new("You have to implement this")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,84 @@
1
+ require 'sum_of_three'
2
+
3
+ module Kata
4
+ module Algorithms
5
+ class SumOfThreeHash < Kata::Algorithms::SumOfThree
6
+ attr_accessor :integer_positions
7
+
8
+ def initialize(array_of_integers)
9
+ super
10
+ self.integer_positions = build_hash(array_of_integers)
11
+ end
12
+
13
+ # Tries to find 3 integers that sum up to 0.
14
+ # In other words given an array a, we want to find
15
+ # the 3 integers that satisfy the equation:
16
+ #
17
+ # a[i] + a[j] + a[k] == 0
18
+ #
19
+ # where i != j && i != k && j !=k
20
+ #
21
+ # This equation can be equally written:
22
+ #
23
+ # a[i] == - a[j] - a[k]
24
+ #
25
+ # Hence, we are looking for pairs of integers in
26
+ # a, let's say a[j] and a[k], that their (- a[j] - a[k]) is
27
+ # another integer in the array.
28
+ #
29
+ # The algorithm will use a hash to store the integers
30
+ # of the array and their position. Then it will iterate
31
+ # all the pairs j, k and will try to see whether their (-a[j]-a[k])
32
+ # is in the hash and in which position.
33
+ # One might say, why do we keep an array of positions of each integer and
34
+ # not just keep a true/false flag to indicate that the result exists in the
35
+ # hash. This is done to avoid cases in which (-a[j]-a[k]) == a[j] or (-a[j]-a[k]) == a[k]
36
+ # For example, if the initial array is [-4, 8, 5], then if we just build the hash
37
+ # h = {-4 => true, 8 => true, 5 => true}, for j == 0 and k == 1, the (-a[j]-a[k]) == (+4-8) == -4
38
+ # and -4 exists in the hash and we falsely get the result -4, -8, -4.
39
+ # If we know that -4 => [0] we can see that 0 is == j and does not count as a valid
40
+ # found position.
41
+ #
42
+ # Note that this algorithm average and worst case performance is O(n^2)
43
+ # Note also that seaching in a hash entry to find a position that is different from j, k at hand
44
+ # is now done with Array#index, which does linear search. If the initial array has a lot of duplicates the search might take long.
45
+ #
46
+ def find_three
47
+ j = 0
48
+ size_of_array = array_of_integers.size
49
+ while j < size_of_array
50
+ k = j + 1
51
+ while k < size_of_array
52
+ i = - array_of_integers[j] - array_of_integers[k]
53
+ hash_entry = integer_positions[i]
54
+ # there has to be at least one integer position in the hash_entry which is not j or k
55
+ return [array_of_integers[j], array_of_integers[k], i] unless hash_entry.nil? || hash_entry.index {|item| ![j, k].include?(item)}.nil?
56
+ k += 1
57
+ end
58
+ j += 1
59
+ end
60
+ []
61
+ end
62
+
63
+ private
64
+
65
+ # Needs to take the input array and create a hash with the
66
+ # positions an integer is found. So, for the array
67
+ #
68
+ # array_of_integers = [3, 2, 8, 3]
69
+ #
70
+ # it will create the hash
71
+ #
72
+ # integer_positions = {3 => [0, 3], 2 => [1], 8 => [2]}
73
+ #
74
+ def build_hash(array_of_integers)
75
+ integer_positions = {}
76
+ array_of_integers.each_with_index do |i, index|
77
+ integer_positions[i] = [] if integer_positions[i].nil?
78
+ integer_positions[i] << index
79
+ end
80
+ integer_positions
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,76 @@
1
+ require 'sum_of_three'
2
+
3
+ module Kata
4
+ module Algorithms
5
+ class SumOfThreeSort < Kata::Algorithms::SumOfThree
6
+
7
+ def initialize(array_of_integers)
8
+ super
9
+ end
10
+
11
+ # Tries to find 3 integers that sum up to 0.
12
+ # In other words given an array a, we want to find
13
+ # the 3 integers that satisfy the equation:
14
+ #
15
+ # a[i] + a[j] + a[k] == 0
16
+ #
17
+ # where i != j && i != k && j !=k
18
+ #
19
+ # The algorithm first sorts the input array, and then follows a clever algorithm that does not have to
20
+ # use any search for pairs.
21
+ #
22
+ # This is the pseudo-algorithm
23
+ #
24
+ # sort(array_of_integers);
25
+ #
26
+ # for i=0 to n-3 do
27
+ # a = S[i];
28
+ # j = i+1;
29
+ # k = size_of_array - 1;
30
+ # while (j < k) do
31
+ # b = S[j];
32
+ # c = S[k];
33
+ # if (a + b + c == 0) then
34
+ # return a, b, c; # This is the happy case and we stop
35
+ # else if (a + b + c > 0) then
36
+ # k = k - 1; # In this case, the b + c is big enough and we need to make it smaller. We know for sure that c is quite big
37
+ # # because it has been set as the value of the element that is on the far right, a.k.a. the biggest one.
38
+ # # So, let us try to use the previous element, which is smaller than c. Hence we will make the (b+c) factor
39
+ # # smaller and the (a + b + c) moving closer to 0.
40
+ # else
41
+ # j = j + 1; # In this case, the b + c is small enough so that the (a + b + c) < 0. We need to increase b + c but
42
+ # # not so much to go over 0. We need to increase it a little bit. That's why we decide to pick up the
43
+ # # next biggest element, which is j + 1.
44
+ # end
45
+ # end
46
+ # end
47
+ #
48
+ def find_three
49
+ array_of_integers.sort!
50
+ i = 0
51
+ size_of_array = array_of_integers.size
52
+ while i <= size_of_array - 3
53
+ a = array_of_integers[i]
54
+ j = i + 1
55
+ k = size_of_array - 1
56
+
57
+ while j < k
58
+ b = array_of_integers[j]
59
+ c = array_of_integers[k]
60
+ sum = a + b + c
61
+ if sum == 0
62
+ return [a, b, c]
63
+ elsif sum > 0
64
+ k -= 1
65
+ else
66
+ j += 1
67
+ end
68
+ end
69
+
70
+ i += 1
71
+ end
72
+ []
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,5 +1,5 @@
1
1
  module Kata
2
2
  module Algorithms
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -0,0 +1,12 @@
1
+ { "examples" :
2
+ [
3
+ {"input" : [], "possible_results" : [[]] },
4
+ {"input" : [1], "possible_results" : [[]] },
5
+ {"input" : [1, 2], "possible_results" : [[]] },
6
+ {"input" : [1, 2, 3], "possible_results" : [[]] },
7
+ {"input" : [3, -2, 1, -1, 0, -2], "possible_results" : [[1, -1, 0], [3, -2, -1]] },
8
+ {"input" : [0, 0, 0], "possible_results" : [[0, 0, 0]] },
9
+ {"input" : [1, 6, 1, 8, -2, -20, 133, 2], "possible_results" : [[1, 1, -2]] },
10
+ {"input" : [-10, 32, -100, 70, -60, -4], "possible_results" : [[-10, 70, -60], [32, 10, -4]] }
11
+ ]
12
+ }
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kata::Algorithms::Sorting do
4
+ subject {
5
+ Kata::Algorithms::Sorting
6
+ }
7
+ context 'when nil array of integers' do
8
+ let(:array_to_sort) { nil }
9
+ it 'sorts the array' do
10
+ expect(subject.insertion_sort(array_to_sort)).to be_nil
11
+ end
12
+ end
13
+ context 'when empty array of integers' do
14
+ let(:array_to_sort) { [] }
15
+ it 'sorts the array' do
16
+ expect(subject.insertion_sort(array_to_sort)).to be_empty
17
+ end
18
+ end
19
+ context 'when array of integers with one element' do
20
+ let(:array_to_sort) { [3] }
21
+ it 'sorts the array' do
22
+ expect(subject.insertion_sort(array_to_sort)).to eq(array_to_sort.sort)
23
+ end
24
+ end
25
+ context 'when array of integers case 1' do
26
+ let(:array_to_sort) { [5, 9, 3, 0, 15, 1, 2] }
27
+ it 'sorts the array' do
28
+ expect(subject.insertion_sort(array_to_sort)).to eq(array_to_sort.sort)
29
+ end
30
+ end
31
+ context 'when array of integers case 2' do
32
+ let(:array_to_sort) { [1, 1] }
33
+ it 'sorts the array' do
34
+ expect(subject.insertion_sort(array_to_sort)).to eq(array_to_sort.sort)
35
+ end
36
+ end
37
+ context 'when array of integers case 3' do
38
+ let(:array_to_sort) { [2, 1] }
39
+ it 'sorts the array' do
40
+ expect(subject.insertion_sort(array_to_sort)).to eq(array_to_sort.sort)
41
+ end
42
+ end
43
+ context 'when array of integers case 4' do
44
+ let(:array_to_sort) { [5, 4, 3, 2, 1] }
45
+ it 'sorts the array' do
46
+ expect(subject.insertion_sort(array_to_sort)).to eq(array_to_sort.sort)
47
+ end
48
+ end
49
+ context 'when array of integers case 5' do
50
+ let(:array_to_sort) { [5, 4, 3, 2, 1, 0, 1, 2, 3, 4] }
51
+ it 'sorts the array' do
52
+ expect(subject.insertion_sort(array_to_sort)).to eq(array_to_sort.sort)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,7 @@
1
+ shared_examples "method that finds three integers summing up to zero" do
2
+ it { expect(example['possible_results'].map{|a| a.sort}).to include(sum_of_three.find_three.sort)}
3
+ end
4
+
5
+ shared_examples "method that builds the integer positions" do
6
+ it { expect(sum_of_three.send(:build_hash, example['input'])).to eq(example['result']) }
7
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ require 'shared_examples'
4
+
5
+ describe Kata::Algorithms::SumOfThreeHash do
6
+ describe '#find_three' do
7
+ examples = Kata::Algorithms::SpecHelper::SumOfThree.read_examples_for_find_three
8
+ examples.each do |exmpl|
9
+ context "from #{exmpl['input']}" do
10
+ it_behaves_like "method that finds three integers summing up to zero" do
11
+ let(:example) { exmpl }
12
+ let(:sum_of_three) { Kata::Algorithms::SumOfThreeHash.new(example['input'])}
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ describe '#build_hash' do
19
+ examples = [
20
+ {'input' => [], 'result' => { }},
21
+ {'input' => [1], 'result' => {1 => [0] }},
22
+ {'input' => [1, 2], 'result' => {1 => [0], 2 => [1] }},
23
+ {'input' => [1, 2, 3], 'result' => {1 => [0], 2 => [1], 3 => [2] }},
24
+ {'input' => [3, -2, 1, -1, 0, -2], 'result' => {3 => [0], -2 => [1, 5], 1 => [2], -1 => [3], 0 => [4] }},
25
+ {'input' => [0, 0, 0], 'result' => {0 => [0, 1, 2] }},
26
+ {'input' => [1, 6, 1, 8, -2, -20, 133, 2], 'result' => {1 => [0, 2], 6 => [1], 8 => [3], -2 => [4], -20 => [5], 133 => [6], 2 => [7]}},
27
+ {'input' => [-10, 32, -100, 70, -60, -4], 'result' => {-10 => [0], 32 => [1], -100 => [2], 70 => [3], -60 => [4], -4 => [5] }}
28
+ ]
29
+ examples.each do |exmpl|
30
+ context "from #{exmpl['input']}" do
31
+ it_behaves_like "method that builds the integer positions" do
32
+ let(:example) { exmpl }
33
+ let(:sum_of_three) { Kata::Algorithms::SumOfThreeHash.new(example['input'])}
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ require 'shared_examples'
4
+
5
+ describe Kata::Algorithms::SumOfThreeSort do
6
+ describe '#find_three' do
7
+ examples = Kata::Algorithms::SpecHelper::SumOfThree.read_examples_for_find_three
8
+ examples.each do |exmpl|
9
+ context "from #{exmpl['input']}" do
10
+ it_behaves_like "method that finds three integers summing up to zero" do
11
+ let(:example) { exmpl }
12
+ let(:sum_of_three) { Kata::Algorithms::SumOfThreeSort.new(example['input'])}
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kata::Algorithms::SumOfThree do
4
+ describe '#find_three' do
5
+ subject { Kata::Algorithms::SumOfThree.new([]) }
6
+ it { expect { subject.find_three }.to raise_error(NotImplementedError) }
7
+ end
8
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,6 @@
1
1
  require 'kata/algorithms'
2
+ ROOT = File.expand_path(File.join(File.expand_path('..', __FILE__), '..'))
3
+ $: << File.join(ROOT, 'spec', 'support')
4
+ $: << File.join(ROOT, 'spec', 'kata', 'algorithms', 'sum_of_three')
5
+ require 'read_examples'
2
6
 
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ module Kata
4
+ module Algorithms
5
+ module SpecHelper
6
+ module SumOfThree
7
+ def self.read_examples(file_name)
8
+ file = File.read(file_name)
9
+ JSON.parse(file)['examples']
10
+ end
11
+
12
+ def self.read_examples_for_find_three
13
+ Kata::Algorithms::SpecHelper::SumOfThree.read_examples(File.join(ROOT, 'spec', 'example_data', 'examples.json'))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kata-algorithms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Panayotis Matsinopoulos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-30 00:00:00.000000000 Z
11
+ date: 2014-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -64,9 +78,22 @@ files:
64
78
  - bin/multiplication
65
79
  - kata-algorithms.gemspec
66
80
  - lib/kata/algorithms.rb
81
+ - lib/kata/algorithms/all.rb
82
+ - lib/kata/algorithms/sorting.rb
83
+ - lib/kata/algorithms/sum_of_three/README.markdown
84
+ - lib/kata/algorithms/sum_of_three/sum_of_three.rb
85
+ - lib/kata/algorithms/sum_of_three/sum_of_three_hash.rb
86
+ - lib/kata/algorithms/sum_of_three/sum_of_three_sort.rb
67
87
  - lib/kata/algorithms/version.rb
88
+ - spec/example_data/examples.json
89
+ - spec/kata/algorithms/sorting_spec.rb
90
+ - spec/kata/algorithms/sum_of_three/shared_examples.rb
91
+ - spec/kata/algorithms/sum_of_three/sum_of_three_hash_spec.rb
92
+ - spec/kata/algorithms/sum_of_three/sum_of_three_sort_spec.rb
93
+ - spec/kata/algorithms/sum_of_three/sum_of_three_spec.rb
68
94
  - spec/kata/algorithms_spec.rb
69
95
  - spec/spec_helper.rb
96
+ - spec/support/read_examples.rb
70
97
  homepage: ''
71
98
  licenses:
72
99
  - MIT
@@ -75,6 +102,9 @@ post_install_message:
75
102
  rdoc_options: []
76
103
  require_paths:
77
104
  - lib
105
+ - lib/kata
106
+ - lib/kata/algorithms
107
+ - lib/kata/algorithms/sum_of_three
78
108
  required_ruby_version: !ruby/object:Gem::Requirement
79
109
  requirements:
80
110
  - - '>='
@@ -93,5 +123,12 @@ specification_version: 4
93
123
  summary: A series of algorithms implementation. This is more of a practice while reading
94
124
  books about algorithms
95
125
  test_files:
126
+ - spec/example_data/examples.json
127
+ - spec/kata/algorithms/sorting_spec.rb
128
+ - spec/kata/algorithms/sum_of_three/shared_examples.rb
129
+ - spec/kata/algorithms/sum_of_three/sum_of_three_hash_spec.rb
130
+ - spec/kata/algorithms/sum_of_three/sum_of_three_sort_spec.rb
131
+ - spec/kata/algorithms/sum_of_three/sum_of_three_spec.rb
96
132
  - spec/kata/algorithms_spec.rb
97
133
  - spec/spec_helper.rb
134
+ - spec/support/read_examples.rb