kata-algorithms 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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