Skip to content

Commit

Permalink
circular-array-rotation: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kaiosilveira committed Nov 8, 2023
1 parent b66ca34 commit 878c462
Show file tree
Hide file tree
Showing 8 changed files with 10,298 additions and 0 deletions.
115 changes: 115 additions & 0 deletions circular-array-rotation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Challenge name

Challenge URL:

Challenge description goes here

**Example**

| input | expected result |
| ----- | --------------- |
| 'abc' | 5 |
| 'def' | 3 |
| 'ghi' | 5 |

**Constraints**

- $1 \leq n \leq 100 $
- $1 \leq m \leq 100 $

## Test suite 🧪

The test suite for this challenge covers the constraints described above and a happy path using the example's data. The tests are:

- `test_raises_ex`
- `test_happy_path`

For the full test suite, see [algorithm.spec.rb](./algorithm.spec.rb).

## Algorithm resolution description 📄

Algorithm resolution description

```ruby
# some ruby code here
```

The final code, including constraint validations, is available [here](./algorithm.rb).

## Samples 🥯

The samples used to run a quick sanity check on the implementation are:

```ruby
samples = [
# add samples here
]
```

Which, after feeding it into our runner:

```ruby
HackerRank::Runner.new(samples).run do |n|
HackerRank::Challenges.challenge_fn(n)
end
```

Gives the following output:

```
➜ ruby ./challenge/index.rb
challenge output
```

A good indicative that the solution looks reasonable.

## Implementation benchmarking & time complexity analysis 📈

Let's now take a look at this implementation and see how it stands from a performance point of view. Below, we have a code analysis and a benchmarking of the solution.

### Code analysis 🕵🏽‍♂️

Code analysis considerations

```ruby
# some code here
```

Which translates to the following expression:

[expression breakdown]

Which means **CONSTANT|LINEAR|QUADRATIC** time complexity.

### Benchmarking 📊

To get a visual feeling of how the function behaves as $n$ increases, a benchmark was run from **BENCHMARK_N_ZERO** up to **BENCHMARK_N_MAX**, resulting in the following chart:

```console
cat ./circular-array-rotation/results.csv | uplot line -d, -w 50 -h 15 -t Results --canvas ascii --xlabel n --ylabel "T(n)"
Results
┌──────────────────────────────────────────────────┐
0.003 │ │
│ .│
│ ._r@@│
│ ._@@@@@TT│
│ . _@@@@@T" │
│ @@@@@@@TT` │
│ ._r@@@@T" │
T(n) │ .\r@@@@T/ │
│ ._r@@@T/` │
│ .._@@@@T"` │
│ .__@@@T/` │
│ ._r@@T"` │
│ ..r@@TT" │
│ __r@T/` │
0 │@@T"` │
└──────────────────────────────────────────────────┘
0 10000
n
```

Which, ignoring eventual CPU fluctuations, matches the given time complexity pattern theoretically demonstrated by the code analysis above.

For the full benchmarking code, see [benchmarking.rb](./benchmarking.rb).
25 changes: 25 additions & 0 deletions circular-array-rotation/benchmarking.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require "benchmark"
require_relative './circularly_rotate_array.rb'
require_relative '../_utils/benchmark.rb'
require_relative '../_utils/array/array.rb'

include ArrayUtils

MAX_N_SIZE = 10000

ENV["CONSTRAINT_ENFORCEMENT_ENABLED"] = "disabled"

def invoke_algorithm_n_times(n)
HackerRank::Algorithms.circularly_rotate_array(
input: create_array_of_random_integers(size: n),
rotations: 2
)
end

HackerRank::Benchmarking.create_time_complexity_analysis(
method_name: :invoke_algorithm_n_times,
n0: 1,
n_max: MAX_N_SIZE,
n_incrementation_step: 1,
file_name: "#{File.expand_path File.dirname(__FILE__)}/results.csv"
)
33 changes: 33 additions & 0 deletions circular-array-rotation/challenge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require_relative './circularly_rotate_array.rb'
require_relative "../_utils/validation/index.rb"

module HackerRank
module Challenges
include HackerRank::Validation

def self.circular_array_rotation(input:, number_of_rotations:, queries:)
validate_inputs(input, number_of_rotations, queries)

rotated = Algorithms.circularly_rotate_array(input: input, rotations: number_of_rotations)
queries.map { |query| rotated[query] }
end

def self.validate_inputs(arr, number_of_rotations, queries)
Validation.ensure_is_array(arr: arr, input_name: "input")
Validation.ensure_array_constraints(input_name: 'input', value: arr, constraints: [1, 10**5])

Validation.ensure_constraint_is_within_range(
constraint_name: "number_of_rotations",
constraint_value: number_of_rotations,
range: [1, 10**5],
)

Validation.ensure_is_array(arr: queries, input_name: "queries")
Validation.ensure_array_constraints(
input_name: 'queries',
value: queries,
constraints: [1, 500]
)
end
end
end
70 changes: 70 additions & 0 deletions circular-array-rotation/challenge.spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require "test/unit"
require_relative "./challenge.rb"
require_relative "../_utils/algorithm-test/index.rb"
require_relative "../_utils/exceptions/exceptions.rb"

module HackerRank
module Challenges
class CircularlyRotateArrayTests < Algorithms::AlgorithmTest
def test_raises_exception_if_input_is_not_an_array
assert_raises_invalid_type &-> {
Challenges.circular_array_rotation(input: 3, number_of_rotations: 2, queries: [1, 2])
}
end

def test_raises_exception_if_input_array_size_is_smaller_than_the_lower_end_constraint
assert_raises_arr_out_of_min_size &-> {
Challenges.circular_array_rotation(input: [], number_of_rotations: 2, queries: [1, 2])
}
end

def test_raises_exception_if_input_array_size_is_greater_than_the_higher_end_constraint
assert_raises_arr_out_of_max_size &-> {
Challenges.circular_array_rotation(
input: create_array_of_random_integers(size: 10**5 + 1),
number_of_rotations: 2,
queries: [1, 2]
)
}
end

def test_raises_exception_if_number_of_rotations_is_smaller_than_the_lower_end_constraint
assert_raises_out_of_constraints &-> {
Challenges.circular_array_rotation(
input: [3, 4, 5], number_of_rotations: 0, queries: [1, 2]
)
}
end

def test_raises_exception_if_number_of_rotations_is_greater_than_the_higher_end_constraint
assert_raises_out_of_constraints &-> {
Challenges.circular_array_rotation(
input: [3, 4, 5], number_of_rotations: 10 ** 5 + 1, queries: [1, 2]
)
}
end

def test_raises_an_exception_if_queries_input_is_not_an_array
assert_raises_invalid_type &-> {
Challenges.circular_array_rotation(input: [3, 4, 5], number_of_rotations: 2, queries: 3)
}
end

def test_raises_exception_if_queries_array_size_is_smaller_than_the_lower_end_constraint
assert_raises_arr_out_of_min_size &-> {
Challenges.circular_array_rotation(input: [3, 4, 5], number_of_rotations: 2, queries: [])
}
end

def test_raises_exception_if_queries_array_size_is_greater_than_the_higher_end_constraint
assert_raises_arr_out_of_max_size &-> {
Challenges.circular_array_rotation(
input: [3, 4, 5],
number_of_rotations: 2,
queries: create_array_of_random_integers(size: 501)
)
}
end
end
end
end
13 changes: 13 additions & 0 deletions circular-array-rotation/circularly_rotate_array.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require_relative "../_utils/exceptions/exceptions.rb"

module HackerRank
module Algorithms
include HackerRank::Exceptions

def self.circularly_rotate_array(input:, rotations: 1)
clone = input.clone
rotations.times { clone = clone.unshift(clone.pop) }
clone
end
end
end
24 changes: 24 additions & 0 deletions circular-array-rotation/circularly_rotate_array.spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require "test/unit"
require_relative "./circularly_rotate_array.rb"
require_relative "../_utils/algorithm-test/index.rb"
require_relative "../_utils/exceptions/exceptions.rb"

module HackerRank
module Algorithms
class CircularlyRotateArrayTests < AlgorithmTest
def test_return_a_clone_of_the_original_input
original_input = [5, 3, 4]
Algorithms.circularly_rotate_array(input: [3, 4, 5])
assert_equal [5, 3, 4], original_input
end

def test_moves_the_last_element_to_the_first_position
assert_equal [5, 3, 4], Algorithms.circularly_rotate_array(input: [3, 4, 5])
end

def test_moves_the_last_element_to_the_first_position_multiple_times
assert_equal [4, 5, 3], Algorithms.circularly_rotate_array(input: [3, 4, 5], rotations: 2)
end
end
end
end
16 changes: 16 additions & 0 deletions circular-array-rotation/index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require_relative './challenge.rb'
require_relative '../_utils/hacker-rank/hacker-rank.rb'

samples = [
HackerRank.create_sample(expected_result: [5, 3], params: [[3, 4, 5], 2, [1, 2]]),
HackerRank.create_sample(expected_result: [10, 20, 30], params: [[10, 20, 30], 3, [0, 1, 2]])
]

HackerRank::Runner.new(samples).run do |*params|
array, number_of_rotations, queries = params
HackerRank::Challenges.circular_array_rotation(
input: array,
number_of_rotations: number_of_rotations,
queries: queries
)
end
Loading

0 comments on commit 878c462

Please sign in to comment.