diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile index bdd6eccd..2eed6d7c 100644 --- a/.gitpod.dockerfile +++ b/.gitpod.dockerfile @@ -1,4 +1,9 @@ -FROM gitpod/workspace-full-vnc +FROM gitpod/workspace-base:2023-10-19-14-24-02 -RUN sudo apt-get update \ - && sudo apt-get install julia -y +ENV JULIA_TMP="julia_tmp.tar.gz" + +RUN test ! -e "${JULIA_TMP}" \ + && curl https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz -sSf -o "${JULIA_TMP}" \ + && tar zxvf ${JULIA_TMP} \ + && rm ${JULIA_TMP} \ + && echo "export PATH=${HOME}/julia-1.9.3/bin/:\$PATH" >> ~/.bashrc diff --git a/src/basic/difference_arr.jl b/src/basic/difference_arr.jl index 005ff439..8ce2dda1 100644 --- a/src/basic/difference_arr.jl +++ b/src/basic/difference_arr.jl @@ -11,9 +11,12 @@ - print array after any numbers of changes - O(N) # Functions - - create_diff_arr(original::Array{T}) - Create difference array for array 'original' - - calculate_arr(diff_arr::Array{T}) - Create a original array from the given difference array - - add_to_arr(diff_arr::Array{T}, l::Int, r::Int, x::Number) - Add x to all elements with index from [l, r] + - create_diff_arr(original::Array{<:Number}) + * Create difference array for array 'original' + - calculate_arr(diff_arr::Array{<:Number}) + * Recreate the original array from the given difference array + - add_to_arr(diff_arr::Array{<:Number}, l::Int, r::Int, x::Number) + * Add x to all elements with index from [l, r] # Contributed by: [Nikola Mircic](https://github.com/Nikola-Mircic) @@ -25,7 +28,7 @@ module DifferenceArray function create_diff_arr(original::Array{T}) where {T<:Number} n = length(original) - diff_arr = Array(original) + diff_arr = copy(original) for i in 2:n diff_arr[i] = original[i] - original[i-1] @@ -40,7 +43,7 @@ end function calculate_arr(diff_arr::Array{T}) where {T<:Number} n = length(diff_arr) - arr = Array(diff_arr) + arr = copy(diff_arr) for i in 2:n arr[i] = diff_arr[i] + arr[i-1] @@ -51,7 +54,7 @@ end # Add x to all elements with index from [l, r] # Parameters: -# - dif_arr - a difference array of the array you want to change +# - diff_arr - a difference array of the array you want to change # - l - leftmost index of the affected range # - r - rightmost index of the affected range # - x - a value to be added to all elements from a given range diff --git a/src/basic/prefix_sum.jl b/src/basic/prefix_sum.jl index 38888ab4..3802c49e 100644 --- a/src/basic/prefix_sum.jl +++ b/src/basic/prefix_sum.jl @@ -1,5 +1,32 @@ +""" + prefix_sum(arr::Vector{<:Number}) + +# Brief +Given an input array of numbers, return an array of the sum of each "prefix" of the input array i.e. +the 1st element, 1st + 2nd element, 1st + 2nd + 3rd, etc. + +This functionality is available in base Julia as `cumsum`. + +# Arguments +- `arr`: an array of numbers + +# Examples +```julia +julia> prefix_sum([1, 2, 3]) +3-element Vector{Int64}: + 1 + 3 + 6 + +julia> prefix_sum([0.0, 10.0, π]) +3-element Vector{Float64}: + 0.0 + 10.0 + 13.141592653589793 +``` +""" function prefix_sum(arr::Vector{T}) where {T<:Number} - pre = [] + pre = T[] preans = zero(T) for i in arr preans += i diff --git a/src/conversions/weight_conversion.jl b/src/conversions/weight_conversion.jl index e4454d59..3e14a7fc 100644 --- a/src/conversions/weight_conversion.jl +++ b/src/conversions/weight_conversion.jl @@ -24,7 +24,7 @@ WEIGHT_TYPE_CHART = Dict{String,Float64}( "atomic-mass-unit" => 1.660540199e-27, ) -function weight_conversion(from_type, to_type, value) +function weight_conversion(value, from_type, to_type) if !haskey(KILOGRAM_CHART, to_type) || !haskey(WEIGHT_TYPE_CHART, from_type) throw( error( diff --git a/src/graph/bfs.jl b/src/graph/bfs.jl index 7d401304..480331d0 100644 --- a/src/graph/bfs.jl +++ b/src/graph/bfs.jl @@ -23,7 +23,13 @@ TheAlgorithms.Graph.bfs(graph, 4) # output -4 1 2 5 3 6 +6-element Vector{Int64}: + 4 + 1 + 2 + 5 + 3 + 6 ``` Contributed by: [Yannick Brenning](https://github.com/ybrenning) @@ -31,6 +37,7 @@ Contributed by: [Yannick Brenning](https://github.com/ybrenning) function bfs(graph::Vector{Vector{Int}}, source::Int = 1) # Use a boolean "visited" array to avoid processing a vertex more than once visited = [false for _ in 1:length(graph)] + result = Vector{Int}() queue = Queue{Int}() enqueue!(queue, source) @@ -39,7 +46,7 @@ function bfs(graph::Vector{Vector{Int}}, source::Int = 1) while length(queue) > 0 curr_v = dequeue!(queue) - print(curr_v, " ") + push!(result, curr_v) # Add every unvisited target to the end of the queue for i in 1:length(graph[curr_v]) @@ -50,5 +57,5 @@ function bfs(graph::Vector{Vector{Int}}, source::Int = 1) end end - return print("\n") + return result end diff --git a/src/graph/dfs.jl b/src/graph/dfs.jl index 18a4e175..3c9be87a 100644 --- a/src/graph/dfs.jl +++ b/src/graph/dfs.jl @@ -23,7 +23,13 @@ dfs(graph, 6) # output -6 5 2 4 3 1 +6-element Vector{Int64}: + 6 + 5 + 2 + 4 + 3 + 1 ``` Contributed by: [Yannick Brenning](https://github.com/ybrenning) @@ -31,6 +37,7 @@ Contributed by: [Yannick Brenning](https://github.com/ybrenning) function dfs(graph::Vector{Vector{Int}}, source::Int = 1) # Use a boolean "visited" array to avoid processing a vertex more than once visited = [false for _ in 1:length(graph)] + result = Vector{Int}() stack = Stack{Int}() push!(stack, source) @@ -39,7 +46,7 @@ function dfs(graph::Vector{Vector{Int}}, source::Int = 1) while length(stack) > 0 curr_v = pop!(stack) - print(curr_v, " ") + push!(result, curr_v) # Add every unvisited target to the top of the stack for i in 1:length(graph[curr_v]) @@ -49,6 +56,5 @@ function dfs(graph::Vector{Vector{Int}}, source::Int = 1) end end end - - return print("\n") + return result end diff --git a/src/longest_increasing_subsequence/binary_search.jl b/src/longest_increasing_subsequence/binary_search.jl index 5660ea38..b8447bec 100644 --- a/src/longest_increasing_subsequence/binary_search.jl +++ b/src/longest_increasing_subsequence/binary_search.jl @@ -1,5 +1,5 @@ """ - lis(arr::Array{Int}, ::Val{:bs}) + lis(arr::Array{<:Integer}, ::Val{:bs}) # Arguments: - `arr`: sequence of integers @@ -23,12 +23,12 @@ https://cp-algorithms.com/sequences/longest_increasing_subsequence.html - [Igor Malheiros](https://github.com/igormalheiros) """ -function lis(arr::Array{Int}, ::Val{:bs}) +function lis(arr::Array{T}, ::Val{:bs}) where T <: Integer len = length(arr) - memo = ones(Int, len) + memo = ones(T, len) p = ones(Int, len) - lis_arr = Int[] + lis_arr = T[] len == 0 && return lis_arr # if `arr` is empty @@ -48,12 +48,10 @@ function lis(arr::Array{Int}, ::Val{:bs}) last_pos = lis_len for i in len:-1:1 if p[i] == last_pos - push!(lis_arr, arr[i]) + pushfirst!(lis_arr, arr[i]) last_pos -= 1 end end - reverse!(lis_arr) - return lis_arr end diff --git a/src/longest_increasing_subsequence/dynamic_programming.jl b/src/longest_increasing_subsequence/dynamic_programming.jl index 4fcc1db8..f8392bb7 100644 --- a/src/longest_increasing_subsequence/dynamic_programming.jl +++ b/src/longest_increasing_subsequence/dynamic_programming.jl @@ -1,5 +1,5 @@ """ - lis(arr::Array{Int}, ::Val{:dp}) + lis(arr::Array{<:Integer}, ::Val{:dp}) # Arguments: - `arr`: sequence of integers @@ -23,12 +23,12 @@ https://cp-algorithms.com/sequences/longest_increasing_subsequence.html - [Igor Malheiros](https://github.com/igormalheiros) """ -function lis(arr::Array{Int}, ::Val{:dp}) +function lis(arr::Array{T}, ::Val{:dp}) where T <: Integer len = length(arr) memo = ones(Int, len) p = zeros(Int, len) - lis_arr = Int[] + lis_arr = T[] len == 0 && return lis_arr # if arr is empty @@ -51,11 +51,9 @@ function lis(arr::Array{Int}, ::Val{:dp}) # Restoring while lis_pos != 0 - push!(lis_arr, arr[lis_pos]) + pushfirst!(lis_arr, arr[lis_pos]) lis_pos = p[lis_pos] end - reverse!(lis_arr) - return lis_arr end diff --git a/src/math/Math.jl b/src/math/Math.jl index c7b93da4..f8c1eb0a 100644 --- a/src/math/Math.jl +++ b/src/math/Math.jl @@ -26,6 +26,9 @@ export area_trapezium export area_triangle export average_absolute_deviation export bab_sqrt +export bin_length +export bin_length_long +export bin_length_short export catalan export ceil export collatz_sequence @@ -60,6 +63,7 @@ export permutation export prime_check export prime_factors export riemann_integration +export runge_kutta_integration export simpsons_integration export sum_ap export sum_gp @@ -89,6 +93,7 @@ include("average_mean.jl") include("average_median.jl") include("average_mode.jl") include("babylonian_sqrt.jl") +include("binary_length.jl") include("catalan_number.jl") include("ceil.jl") # needed by average_median include("collatz_sequence.jl") @@ -111,6 +116,7 @@ include("permutation.jl") include("prime_check.jl") include("prime_factors.jl") include("riemann_integration.jl") +include("runge_kutta_integration.jl") include("sieve_of_eratosthenes.jl") include("simpsons_integration.jl") include("sum_of_arithmetic_series.jl") diff --git a/src/strings/binary_length.jl b/src/math/binary_length.jl similarity index 57% rename from src/strings/binary_length.jl rename to src/math/binary_length.jl index 4f2ae58f..4f2bb5de 100644 --- a/src/strings/binary_length.jl +++ b/src/math/binary_length.jl @@ -1,17 +1,28 @@ -function bin_length_long(s::AbstractString) - binNum = parse(UInt, s) - - finNum = 0 - seq = 1 - - for i in 1:binNum - if (i == seq) - finNum += 1 - seq *= 2 - end - end - - return string(finNum) +""" + bin_length(binNum) +Returns the length of binNum's binary representation. + +# Input parameters: +- `binNum` : The number to find the binary length of. + +# Examples/Tests: +```julia +bin_length(1) # returns 1 +bin_length(2) # returns 2 +bin_length(3) # returns 2 +bin_length(4) # returns 3 +bin_length(5) # returns 3 +bin_length(12) # returns 4 +bin_length(256) # returns 9 +bin_length(1024) # returns 11 +bin_length(-1) # throws DomainError +``` + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function bin_length(binNum::T) where {T<:Integer} + binNum <= 0 && throw(DomainError("binNum must be a positive integer")) + return floor(log2(binNum)) + 1 end """ @@ -46,19 +57,20 @@ doubled amount. #Contributions: Contributed by F35H: https://github.com/F35H """ - -function bin_length_short(s::AbstractString) - binNum = parse(UInt, s) +function bin_length_long(binNum::T) where {T<:Integer} + binNum <= 0 && throw(DomainError("binNum must be a positive integer")) finNum = 0 - i = 1 + seq = 1 - while i <= binNum - i *= 2 - finNum += 1 + for i in 1:binNum + if (i == seq) + finNum += 1 + seq *= 2 + end end - return string(finNum) + return finNum end """ @@ -68,7 +80,7 @@ the length of any binary number and returns said length. https://oeis.org/A070939 -This function, as believed, is O(n) +This function, as believed, is O(log(n)) The idea follows that the sequence is dependent on a repeating pattern of 2. The final number being finNum @@ -90,3 +102,16 @@ final number that iterates on every doubling of i. Contributors: - [F45H](https://github.com/F35H) """ +function bin_length_short(binNum::T) where {T<:Integer} + binNum <= 0 && throw(DomainError("binNum must be a positive integer")) + + finNum = 0 + i = 1 + + while i <= binNum + i *= 2 + finNum += 1 + end + + return finNum +end diff --git a/src/math/fibonacci.jl b/src/math/fibonacci.jl index d3f59f7b..6d9d86cc 100644 --- a/src/math/fibonacci.jl +++ b/src/math/fibonacci.jl @@ -98,8 +98,6 @@ function fib_iterative(n::Int) throw(DomainError("n is negative")) elseif n == 1 return [0] - elseif n == 2 - return [0, 1] else result = [0, 1] a, b = 0, 1 diff --git a/src/math/runge_kutta_integration.jl b/src/math/runge_kutta_integration.jl new file mode 100644 index 00000000..c8e2fd36 --- /dev/null +++ b/src/math/runge_kutta_integration.jl @@ -0,0 +1,83 @@ +""" + runge_kutta_integration(f::Function, x0::Real, y0::Real, h::Real, x_stop::Real) + +Numerically solve initial value problems of the form ``y' = f(x, y)`` to find ``y(x)`` using the Runge-Kutta 4th order integration scheme. + +Starting with the differential equation ``\\frac{\\mathrm{d}y}{\\mathrm{d}x} = y' = f(x, y)`` and the initial condition ``y(x_0) = y_0``, each step calculates 4 approximations of the gradient +```math +\\begin{align*} + k_1 &= f(x_n, y_n),\\\\ + k_2 &= f(x_n + \\frac{h}{2}, y_n + k_1\\frac{h}{2}),\\\\ + k_3 &= f(x_n + \\frac{h}{2}, y_n + k_2\\frac{h}{2}),\\\\ + k_4 &= f(x_n + h, y_n + k_3h), +\\end{align*} +``` +and uses the weighted average of them, + +```math +\\bar{k} = \\frac{k_1 + 2k_2 + 2k_3 + k_4}{6}, +``` + +to find the approximate value of ``y(x_{n+1})`` and update ``x`` and ``y`` accordingly + +```math +\\begin{align*} + x &\\rightarrow x_{n+1} = x_n + h\\\\ + y &\\rightarrow y_{n+1} = y_n + h\\bar{k}. +\\end{align*} +``` + +# Arguments: +- `f`: The function ``y' = f(x, y)`` to solve for ``y(x)``. +- `x0`: The starting value of x. +- `y0`: The starting value of y. +- `h`: The step size, should be >0. +- `x_stop`: The final value of x to solve to, i.e. integrate over the range `[x0, x_stop]` + +# Examples +```julia +julia> # If you have a constant slope of y' = 1, the analytic solution is y = x +julia> runge_kutta_integration((x, y)->1, 0, 0, 1, 3) +([0.0, 1.0, 2.0, 3.0], [0.0, 1.0, 2.0, 3.0]) + +julia> # Consider solving y' = exp(x), which has the analytic solution y = exp(x). +julia> runge_kutta_integration((x, y)->exp(x), 0, 1., 0.1, 0.1) +([0.0, 0.1], [1.0, 1.105170921726329]) + +julia> exp.([0.0, 0.1]) +2-element Vector{Float64}: + 1.0 + 1.1051709180756477 + +``` + +# References + - [https://en.wikipedia.org/wiki/Initial_value_problem](https://en.wikipedia.org/wiki/Initial_value_problem) + - [https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods](https://en.wikipedia.org/wiki/Initial_value_problem) + +# Contributors: +- [E-W-Jones](https://github.com/E-W-Jones) +""" +function runge_kutta_integration(f::Function, x0::Real, y0::Real, h::Real, x_stop::Real) + h > 0 || throw(DomainError(h, "The step size `h` should be >0.")) + + x = Float64(x0) + y = Float64(y0) + output_x = [x] + output_y = [y] + + while x < x_stop + k1 = f(x, y) + k2 = f(x + h/2, y + k1*h/2) + k3 = f(x + h/2, y + k2*h/2) + k4 = f(x + h , y + k3*h ) + + y += h * (k1 + 2k2 + 2k3 + k4) / 6 + x += h + + push!(output_x, x) + push!(output_y, y) + end + + return output_x, output_y +end \ No newline at end of file diff --git a/src/matrix/determinant.jl b/src/matrix/determinant.jl index b4bf2faf..751a63c8 100644 --- a/src/matrix/determinant.jl +++ b/src/matrix/determinant.jl @@ -16,7 +16,7 @@ Determinant of triangualar matrices is the product of their diagonal entries. He function determinant(mat) n, m = size(mat) if n != m - DomainError(mat, "The matrix should be a square matrix.") + throw(DomainError(mat, "The matrix should be a square matrix.")) end L, U = lu_decompose(mat) l_prod = prod([L[i, i] for i in 1:n]) diff --git a/src/project_euler/ProjectEuler.jl b/src/project_euler/ProjectEuler.jl index 62932fc5..c399e487 100644 --- a/src/project_euler/ProjectEuler.jl +++ b/src/project_euler/ProjectEuler.jl @@ -19,6 +19,12 @@ export problem_011 export problem_012 export problem_013 export problem_014 +export problem_015 +export problem_016 +export problem_017 +export problem_018 +export problem_019 +export problem_020 include("../math/divisors.jl") include("../math/sieve_of_eratosthenes.jl") @@ -36,5 +42,11 @@ include("problem_011.jl") include("problem_012.jl") include("problem_013.jl") include("problem_014.jl") +include("problem_015.jl") +include("problem_016.jl") +include("problem_017.jl") +include("problem_018.jl") +include("problem_019.jl") +include("problem_020.jl") end diff --git a/src/project_euler/problem_010.jl b/src/project_euler/problem_010.jl index 05416c7d..83a99426 100644 --- a/src/project_euler/problem_010.jl +++ b/src/project_euler/problem_010.jl @@ -23,5 +23,5 @@ Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) """ function problem_010(n::Int) n < 1 && throw(DomainError("n must be a natural number")) - return reduce(+, eratosthenes(Int64(n)), init=Int64(0)) + return reduce(+, eratosthenes(Int64(n)), init = Int64(0)) end diff --git a/src/project_euler/problem_015.jl b/src/project_euler/problem_015.jl new file mode 100644 index 00000000..6f0ba456 --- /dev/null +++ b/src/project_euler/problem_015.jl @@ -0,0 +1,36 @@ +""" + Lattice Paths + +Starting in the top left corner of a grid, and only being able to move to the +right and down, there are exactly 6 routes to the bottom right corner. How many +such routes are there through a 20 x 20 grid? +grid? + +# Input parameters: +- `n` : number of rows in the grid +- `m` : number of columns in the grid + +# Examples/Tests: +```julia +problem_015(2, 2) # returns 6 +problem_015(5, 3) # returns 56 +problem_015(20, 20) # returns 137846528820 +problem_015(0, 5) # throws DomainError +problem_015(-3, 0) # throws DomainError +``` + +# Reference +- https://projecteuler.net/problem=15 + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function problem_015(n::T, m::T) where {T<:Integer} + #= + The path is a combination of rights and downs, with a total of n + m operations + We need to count the number of such combinations of n rights and m downs + This is equivalent to finding the binomial coefficient (n+m, m) or (n+m, n) + Note that both of them are equivalent + =# + (n <= 1 || m <= 1) && throw(DomainError("n and m must be greater than 1")) + return binomial(BigInt(n + m), BigInt(n)) +end diff --git a/src/project_euler/problem_016.jl b/src/project_euler/problem_016.jl new file mode 100644 index 00000000..de0518cf --- /dev/null +++ b/src/project_euler/problem_016.jl @@ -0,0 +1,28 @@ +""" + Power Digit Sum + +2^15 = 32768 and the sum of its digits is 3+2+7+6+8=26. +What is the sum of the digits of the number 2^1000? +grid? + +# Input parameters: +- `a` : base +- `n` : exponent + +# Examples/Tests: +```julia +problem_016(1, 1) # returns 1 +problem_016(2, 15) # returns 26 +problem_016(2, 1000) # returns 1366 +problem_016(2, -4) # throws DomainError +``` + +# Reference +- https://projecteuler.net/problem=16 + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function problem_016(a::T, n::T) where {T<:Integer} + (a <= 0 || n <= 0) && throw(DomainError("a and n must be greater than 1")) + return sum(parse(Int, digit) for digit in string(big(a)^n)) +end diff --git a/src/project_euler/problem_017.jl b/src/project_euler/problem_017.jl new file mode 100644 index 00000000..b3b9676e --- /dev/null +++ b/src/project_euler/problem_017.jl @@ -0,0 +1,68 @@ +""" + Number Letter Counts + +If the numbers 1 to 5 are written out in words, then there are 3+3+5+4+4=19 letters used in total. +If all the numbers from 1 to 1000 inclusive were written out in words, how many letters would be used? + +# Examples/Tests: +```julia +problem_017() # returns 21124 +``` + +# Reference +- https://projecteuler.net/problem=17 + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function problem_017() + # Hardcore letter counts for unpredictable values + letter_count = Dict( + 0 => 0, # Base case + 1 => 3, # "one" + 2 => 3, # "two" + 3 => 5, # "three" + 4 => 4, # "four" + 5 => 4, # "five" + 6 => 3, # "six" + 7 => 5, # "seven" + 8 => 5, # "eight" + 9 => 4, # "nine" + 10 => 3, # "ten" + 11 => 6, # "eleven" + 12 => 6, # "twelve" + 13 => 8, # "thirteen" + 14 => 8, # "fourteen" + 15 => 7, # "fifteen" + 16 => 7, # "sixteen" + 17 => 9, # "seventeen" + 18 => 8, # "eighteen" + 19 => 8, # "nineteen" + 20 => 6, # "twenty" + 30 => 6, # "thirty" + 40 => 5, # "forty" + 50 => 5, # "fifty" + 60 => 5, # "sixty" + 70 => 7, # "seventy" + 80 => 6, # "eighty" + 90 => 6, # "ninety" + 1000 => 11, # "one thousand" + ) + + # For two digit numbers, add the tens place count and the units place count + for num in 21:99 + letter_count[num] = letter_count[num-num%10] + letter_count[num%10] + end + + # For three digit numbers, add the hundreds digit and then the rest + for num in 100:999 + hundreds_digit = num ÷ 100 + rest = num % 100 + letter_count[num] = + letter_count[hundreds_digit] + letter_count[rest] + 7 # 7 for the "hundred" + if rest > 0 + letter_count[num] += 3 # 3 for the "and" + end + end + + return sum(values(letter_count)) +end diff --git a/src/project_euler/problem_018.jl b/src/project_euler/problem_018.jl new file mode 100644 index 00000000..1433408d --- /dev/null +++ b/src/project_euler/problem_018.jl @@ -0,0 +1,66 @@ +""" + Maximum Path Sum I + +By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23. + + 3 + 7 4 + 2 4 6 + 8 5 9 3 + +Find the maximum total from top to bottom of the triangle below. + +# Examples/Tests: +```julia +problem_018() # returns 1074 +``` + +# Reference +- https://projecteuler.net/problem=18 + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function problem_018() + triangle = [ + [75], + [95 64], + [17 47 82], + [18 35 87 10], + [20 04 82 47 65], + [19 01 23 75 03 34], + [88 02 77 73 07 63 67], + [99 65 04 28 06 16 70 92], + [41 41 26 56 83 40 80 70 33], + [41 48 72 33 47 32 37 16 94 29], + [53 71 44 65 25 43 91 52 97 51 14], + [70 11 33 28 77 73 17 78 39 68 17 57], + [91 71 52 38 17 14 91 43 58 50 27 29 48], + [63 66 04 68 89 53 67 30 73 16 69 87 40 31], + [04 62 98 27 23 09 70 98 73 93 38 53 60 04 23], + ] + + #= + We create a dp table, where the state dp[i][j] is the maximum sum ending at (i, j). + The transition is dp[i][j] = triangle[i][j] + max(dp[i-1][j-1], dp[i-1][j]). + We then return the max of the last row, which is the required maximum total. + =# + + dp = deepcopy(triangle) + for (row_num, row) in enumerate(triangle) + row_num == 1 && continue + for col_num in eachindex(row) + if col_num == 1 + prev_best = dp[row_num-1][col_num] + elseif col_num == row_num + prev_best = dp[row_num-1][col_num-1] + else + prev_best = + max(dp[row_num-1][col_num], dp[row_num-1][col_num-1]) + end + + dp[row_num][col_num] += prev_best + end + end + + return maximum(last(dp)) +end diff --git a/src/project_euler/problem_019.jl b/src/project_euler/problem_019.jl new file mode 100644 index 00000000..ed701c38 --- /dev/null +++ b/src/project_euler/problem_019.jl @@ -0,0 +1,73 @@ +""" + Counting Sundays + +How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)? + +# Input parameters: +- `start_year` : start from 1st January of start_year +- `end_year` : check till 31st December of end_year + +# Examples/Tests: +```julia +problem_019(1901, 2000) # returns 171 +problem_019(1901, 2200) # returns 515 +problem_019(2020, 2023) # returns 6 +problem_019(-1, 2023) # throws DomainError +``` + +# Reference +- https://projecteuler.net/problem=19 + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function problem_019(start_year::T, end_year::T) where {T<:Integer} + (start_year <= 0 || end_year <= 0) && + throw(DomainError("years must be greater than 1")) + + days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + + res = 0 + cur_day = zeller_congruence(1, 1, start_year) + is_leap(year) = year % 400 == 0 || (year % 100 != 0 && year % 4 == 0) + for year in start_year:end_year + for (month_index, num_days) in enumerate(days_in_month) + cur_day += num_days + if month_index == 2 && is_leap(year) # Leap year and February + cur_day += 1 # then extra day + end + cur_day %= 7 + res += cur_day == 0 + end + end + + return res +end + +""" + Zeller's Congruence + +Given a date, returns the day of the week + +0 => Sunday 1 => Monday, 2 => Tuesday, ... , 6 => Saturday + +# Input parameters: +- `day` : day of the month +- `month` : month of the year (1 indexed) +- `year` : year + +# Reference +- https://en.wikipedia.org/wiki/Zeller%27s_congruence +""" +function zeller_congruence(day::T, month::T, year::T) where {T<:Integer} + if month <= 2 + month += 12 # January and February are counted as the previous year's 13th and 14th month + year -= 1 + end + q = day + m = month + K = year % 100 + J = year ÷ 100 + + h = q + (13 * (m + 1)) ÷ 4 + K + K ÷ 4 + J ÷ 4 - 2 * J + return (h + 4) % 7 +end diff --git a/src/project_euler/problem_020.jl b/src/project_euler/problem_020.jl new file mode 100644 index 00000000..f136e318 --- /dev/null +++ b/src/project_euler/problem_020.jl @@ -0,0 +1,29 @@ +""" + Factorial Digit Sum + +Find the sum of the digits in the number 100!. + +# Input parameters: +- `n` : number to find sum of digits of factorial of + +# Examples/Tests: +```julia +problem_020(10) # returns 27 +problem_020(37) # returns 153 +problem_020(100) # returns 648 +problem_020(-1) # throws DomainError +``` + +# Reference +- https://projecteuler.net/problem=20 + +Contributed by: [Praneeth Jain](https://www.github.com/PraneethJain) +""" +function problem_020(n::T) where {T<:Integer} + n < 0 && throw(DomainError("n must be a non-negative integer")) + return mapreduce( + x -> Int(x) - Int('0'), + +, + collect(string(factorial(big(n)))), + ) +end diff --git a/src/searches/binary_search.jl b/src/searches/binary_search.jl index 6928c286..bf895495 100644 --- a/src/searches/binary_search.jl +++ b/src/searches/binary_search.jl @@ -67,15 +67,14 @@ function binary_search( ) where {T<:Real} if (r >= l) mid = Int(ceil(l + (r - l) / 2)) - # println(mid) if (arr[mid] == x) - return "Element present at index $mid" + return mid elseif (arr[mid] > x) binary_search(arr, l, mid - 1, x) else binary_search(arr, mid + 1, r, x) end else - return "Element not present in array" + return -1 end end diff --git a/src/searches/exponential_search.jl b/src/searches/exponential_search.jl index 19c09152..2af76c48 100644 --- a/src/searches/exponential_search.jl +++ b/src/searches/exponential_search.jl @@ -19,7 +19,7 @@ Contributed By:- [Ash](https://github.com/ashwani-rathee) function exponential_search(arr::AbstractArray{T,1}, x::T) where {T<:Real} n = size(arr)[1] if (arr[1] == x) - return "Element present at index 1" + return 1 end i = 1 diff --git a/src/searches/interpolation_search.jl b/src/searches/interpolation_search.jl index 88eb7b6e..ae30a236 100644 --- a/src/searches/interpolation_search.jl +++ b/src/searches/interpolation_search.jl @@ -46,13 +46,13 @@ function interpolation_search( if (r >= l && x >= arr[l] && x <= arr[r]) mid = Int(ceil(l + (((x - arr[l]) * (r - l)) / (arr[r] - arr[l])))) if (arr[mid] == x) - return "Element present at index $mid" + return mid elseif (arr[mid] > x) interpolation_search(arr, l, mid - 1, x) else interpolation_search(arr, mid + 1, r, x) end else - return "Element not present in array" + return -1 end end diff --git a/src/sorts/heap_sort.jl b/src/sorts/heap_sort.jl index e80cfd90..71a19bb2 100644 --- a/src/sorts/heap_sort.jl +++ b/src/sorts/heap_sort.jl @@ -28,6 +28,9 @@ After the largest element has been extracted, the tree is updated to maintain th Contributed By:- [Frank Schmitt](https://github.com/frankschmitt) """ function heap_sort!(arr::Vector{T}, gt = >, N::Int = length(arr)) where {T} + if isempty(arr) + return + end n = N i = div(n, 2) t = -1 diff --git a/test/basic.jl b/test/basic.jl index 05cb6a85..edfa1c29 100644 --- a/test/basic.jl +++ b/test/basic.jl @@ -4,6 +4,9 @@ using TheAlgorithms.Basic @testset "Basic: prefix_sum" begin @test Basic.prefix_sum([1, 1, 1]) == [1, 2, 3] @test Basic.prefix_sum([1, 2, 3]) == [1, 3, 6] + @test Basic.prefix_sum(BigInt[]) == BigInt[] + @test Basic.prefix_sum([0., 0., 0.]) == [0., 0., 0.] + @test Basic.prefix_sum([1 + 2im, 2 - 3im]) == [1 + 2im, 3 - 1im] end @testset "Basic: DifferenceArray" begin diff --git a/test/cipher.jl b/test/cipher.jl index b92ae593..c7141462 100644 --- a/test/cipher.jl +++ b/test/cipher.jl @@ -10,10 +10,15 @@ using TheAlgorithms.Cipher end @testset "Cipher: caesar" begin - input = "stealth" - @test caesar(0, input) == "stealth" - input = "ghsozhv" - @test caesar(90, input) == "stealth" + @test caesar(0, "stealth") == "stealth" + @test caesar(90, "ghsozhv") == "stealth" + + @test caesar(1, "ABC") == "BCD" + @test caesar(-1, "BCD") == "ABC" + + @test caesar(2, "f(x)") == "h(z)" + + @test caesar(5, 'a') == 'f' # rot = 13 # s = "abcdefghijklmnopqrstuvwxyz" diff --git a/test/conversions.jl b/test/conversions.jl index 756338e1..a5ce49a8 100644 --- a/test/conversions.jl +++ b/test/conversions.jl @@ -2,128 +2,130 @@ using TheAlgorithms.Conversions @testset "Conversions" begin @testset "Conversions: Weight Conversions" begin - @test weight_conversion("kilogram", "kilogram", 4) == 4 - @test weight_conversion("kilogram", "gram", 1) == 1000 - @test weight_conversion("kilogram", "milligram", 4) == 4000000 - @test weight_conversion("kilogram", "metric-ton", 4) ≈ 0.004 - @test weight_conversion("kilogram", "long-ton", 3) == 0.0029526219 - @test weight_conversion("kilogram", "short-ton", 1) == 0.0011023122 - @test weight_conversion("kilogram", "pound", 4) == 8.8184976808 - @test weight_conversion("kilogram", "ounce", 4) == 141.095962892 - @test weight_conversion("kilogram", "carrat", 3) == 15000 - @test weight_conversion("kilogram", "atomic-mass-unit", 1) == + @test weight_conversion(4, "kilogram", "kilogram") == 4 + @test weight_conversion(1, "kilogram", "gram") == 1000 + @test weight_conversion(4, "kilogram", "milligram") == 4000000 + @test weight_conversion(4, "kilogram", "metric-ton") ≈ 0.004 + @test weight_conversion(3, "kilogram", "long-ton") == 0.0029526219 + @test weight_conversion(1, "kilogram", "short-ton") == 0.0011023122 + @test weight_conversion(4, "kilogram", "pound") == 8.8184976808 + @test weight_conversion(4, "kilogram", "ounce") == 141.095962892 + @test weight_conversion(3, "kilogram", "carrat") == 15000 + @test weight_conversion(1, "kilogram", "atomic-mass-unit") == 6.022136652e+26 - @test weight_conversion("gram", "kilogram", 1) ≈ 0.001 - @test weight_conversion("gram", "gram", 3) ≈ 3.0 - @test weight_conversion("gram", "milligram", 2) ≈ 2000.0 - @test weight_conversion("gram", "metric-ton", 4) ≈ 4e-06 - @test weight_conversion("gram", "long-ton", 3) ≈ 2.9526219e-06 - @test weight_conversion("gram", "short-ton", 3) ≈ 3.3069366000000003e-06 - @test weight_conversion("gram", "pound", 3) ≈ 0.0066138732606 - @test weight_conversion("gram", "ounce", 1) ≈ 0.035273990723 - @test weight_conversion("gram", "carrat", 2) ≈ 10.0 - @test weight_conversion("gram", "atomic-mass-unit", 1) ≈ 6.022136652e+23 - @test weight_conversion("milligram", "kilogram", 1) ≈ 1e-06 - @test weight_conversion("milligram", "gram", 2) ≈ 0.002 - @test weight_conversion("milligram", "milligram", 3) ≈ 3.0 - @test weight_conversion("milligram", "metric-ton", 3) ≈ 3e-09 - @test weight_conversion("milligram", "long-ton", 3) ≈ 2.9526219e-09 - @test weight_conversion("milligram", "short-ton", 1) ≈ 1.1023122e-09 - @test weight_conversion("milligram", "pound", 3) ≈ + @test weight_conversion(1, "gram", "kilogram") ≈ 0.001 + @test weight_conversion(3, "gram", "gram") ≈ 3.0 + @test weight_conversion(2, "gram", "milligram") ≈ 2000.0 + @test weight_conversion(4, "gram", "metric-ton") ≈ 4e-06 + @test weight_conversion(3, "gram", "long-ton") ≈ 2.9526219e-06 + @test weight_conversion(3, "gram", "short-ton") ≈ 3.3069366000000003e-06 + @test weight_conversion(3, "gram", "pound") ≈ 0.0066138732606 + @test weight_conversion(1, "gram", "ounce") ≈ 0.035273990723 + @test weight_conversion(2, "gram", "carrat") ≈ 10.0 + @test weight_conversion(1, "gram", "atomic-mass-unit") ≈ 6.022136652e+23 + @test weight_conversion(1, "milligram", "kilogram") ≈ 1e-06 + @test weight_conversion(2, "milligram", "gram") ≈ 0.002 + @test weight_conversion(3, "milligram", "milligram") ≈ 3.0 + @test weight_conversion(3, "milligram", "metric-ton") ≈ 3e-09 + @test weight_conversion(3, "milligram", "long-ton") ≈ 2.9526219e-09 + @test weight_conversion(1, "milligram", "short-ton") ≈ 1.1023122e-09 + @test weight_conversion(3, "milligram", "pound") ≈ 6.6138732605999995e-06 - @test weight_conversion("milligram", "ounce", 2) ≈ 7.054798144599999e-05 - @test weight_conversion("milligram", "carrat", 1) ≈ 0.005 - @test weight_conversion("milligram", "atomic-mass-unit", 1) ≈ + @test weight_conversion(2, "milligram", "ounce") ≈ 7.054798144599999e-05 + @test weight_conversion(1, "milligram", "carrat") ≈ 0.005 + @test weight_conversion(1, "milligram", "atomic-mass-unit") ≈ 6.022136652e+20 - @test weight_conversion("metric-ton", "kilogram", 2) == 2000 - @test weight_conversion("metric-ton", "gram", 2) ≈ 2000000 - @test weight_conversion("metric-ton", "milligram", 3) ≈ 3000000000 - @test weight_conversion("metric-ton", "metric-ton", 2) ≈ 2.0 - @test weight_conversion("metric-ton", "long-ton", 3) ≈ 2.9526219 - @test weight_conversion("metric-ton", "short-ton", 2) ≈ 2.2046244 - @test weight_conversion("metric-ton", "pound", 3) ≈ 6613.8732606 - @test weight_conversion("metric-ton", "ounce", 4) ≈ 141095.96289199998 - @test weight_conversion("metric-ton", "carrat", 4) ≈ 20000000 - @test weight_conversion("metric-ton", "atomic-mass-unit", 1) ≈ + @test weight_conversion(2, "metric-ton", "kilogram") == 2000 + @test weight_conversion(2, "metric-ton", "gram") ≈ 2000000 + @test weight_conversion(3, "metric-ton", "milligram") ≈ 3000000000 + @test weight_conversion(2, "metric-ton", "metric-ton") ≈ 2.0 + @test weight_conversion(3, "metric-ton", "long-ton") ≈ 2.9526219 + @test weight_conversion(2, "metric-ton", "short-ton") ≈ 2.2046244 + @test weight_conversion(3, "metric-ton", "pound") ≈ 6613.8732606 + @test weight_conversion(4, "metric-ton", "ounce") ≈ 141095.96289199998 + @test weight_conversion(4, "metric-ton", "carrat") ≈ 20000000 + @test weight_conversion(1, "metric-ton", "atomic-mass-unit") ≈ 6.022136652e+29 - @test weight_conversion("long-ton", "kilogram", 4) == 4064.18432 - @test weight_conversion("long-ton", "gram", 4) == 4064184.32 - @test weight_conversion("long-ton", "milligram", 3) == 3048138240.0 - @test weight_conversion("long-ton", "metric-ton", 4) ≈ 4.06418432 - @test weight_conversion("long-ton", "long-ton", 3) == 2.999999907217152 - @test weight_conversion("long-ton", "short-ton", 1) == 1.119999989746176 - @test weight_conversion("long-ton", "pound", 3) == 6720.000000049448 - @test weight_conversion("long-ton", "ounce", 1) == 35840.000000060514 - @test weight_conversion("long-ton", "carrat", 4) == 20320921.599999998 - @test weight_conversion("long-ton", "atomic-mass-unit", 4) == + @test weight_conversion(4, "long-ton", "kilogram") == 4064.18432 + @test weight_conversion(4, "long-ton", "gram") == 4064184.32 + @test weight_conversion(3, "long-ton", "milligram") == 3048138240.0 + @test weight_conversion(4, "long-ton", "metric-ton") ≈ 4.06418432 + @test weight_conversion(3, "long-ton", "long-ton") == 2.999999907217152 + @test weight_conversion(1, "long-ton", "short-ton") == 1.119999989746176 + @test weight_conversion(3, "long-ton", "pound") == 6720.000000049448 + @test weight_conversion(1, "long-ton", "ounce") == 35840.000000060514 + @test weight_conversion(4, "long-ton", "carrat") == 20320921.599999998 + @test weight_conversion(4, "long-ton", "atomic-mass-unit") == 2.4475073353955697e+30 - @test weight_conversion("short-ton", "kilogram", 3) == + @test weight_conversion(3, "short-ton", "kilogram") == 2721.5519999999997 - @test weight_conversion("short-ton", "gram", 3) == 2721552.0 - @test weight_conversion("short-ton", "milligram", 1) == 907184000.0 - @test weight_conversion("short-ton", "metric-ton", 4) ≈ 3.628736 - @test weight_conversion("short-ton", "long-ton", 3) == 2.6785713457296 - @test weight_conversion("short-ton", "short-ton", 3) == 2.9999999725344 - @test weight_conversion("short-ton", "pound", 2) == 4000.0000000294335 - @test weight_conversion("short-ton", "ounce", 4) == 128000.00000021611 - @test weight_conversion("short-ton", "carrat", 4) == 18143680.0 - @test weight_conversion("short-ton", "atomic-mass-unit", 1) == + @test weight_conversion(3, "short-ton", "gram") == 2721552.0 + @test weight_conversion(1, "short-ton", "milligram") == 907184000.0 + @test weight_conversion(4, "short-ton", "metric-ton") ≈ 3.628736 + @test weight_conversion(3, "short-ton", "long-ton") == 2.6785713457296 + @test weight_conversion(3, "short-ton", "short-ton") == 2.9999999725344 + @test weight_conversion(2, "short-ton", "pound") == 4000.0000000294335 + @test weight_conversion(4, "short-ton", "ounce") == 128000.00000021611 + @test weight_conversion(4, "short-ton", "carrat") == 18143680.0 + @test weight_conversion(1, "short-ton", "atomic-mass-unit") == 5.463186016507968e+29 - @test weight_conversion("pound", "kilogram", 4) == 1.814368 - @test weight_conversion("pound", "gram", 2) == 907.184 - @test weight_conversion("pound", "milligram", 3) == 1360776.0 - @test weight_conversion("pound", "metric-ton", 3) ≈ 0.001360776 - @test weight_conversion("pound", "long-ton", 2) == 0.0008928571152432 - @test weight_conversion("pound", "short-ton", 1) == 0.0004999999954224 - @test weight_conversion("pound", "pound", 3) == 3.0000000000220752 - @test weight_conversion("pound", "ounce", 1) == 16.000000000027015 - @test weight_conversion("pound", "carrat", 1) == 2267.96 - @test weight_conversion("pound", "atomic-mass-unit", 4) == + @test weight_conversion(4, "pound", "kilogram") == 1.814368 + @test weight_conversion(2, "pound", "gram") == 907.184 + @test weight_conversion(3, "pound", "milligram") == 1360776.0 + @test weight_conversion(3, "pound", "metric-ton") ≈ 0.001360776 + @test weight_conversion(2, "pound", "long-ton") == 0.0008928571152432 + @test weight_conversion(1, "pound", "short-ton") == 0.0004999999954224 + @test weight_conversion(3, "pound", "pound") == 3.0000000000220752 + @test weight_conversion(1, "pound", "ounce") == 16.000000000027015 + @test weight_conversion(1, "pound", "carrat") == 2267.96 + @test weight_conversion(4, "pound", "atomic-mass-unit") == 1.0926372033015936e+27 - @test weight_conversion("ounce", "kilogram", 3) == 0.0850485 - @test weight_conversion("ounce", "gram", 3) == 85.0485 - @test weight_conversion("ounce", "milligram", 4) == 113398.0 - @test weight_conversion("ounce", "metric-ton", 4) ≈ 0.000113398 - @test weight_conversion("ounce", "long-ton", 4) == 0.0001116071394054 - @test weight_conversion("ounce", "short-ton", 4) == 0.0001249999988556 - @test weight_conversion("ounce", "pound", 1) == 0.0625000000004599 - @test weight_conversion("ounce", "ounce", 2) == 2.000000000003377 - @test weight_conversion("ounce", "carrat", 1) == 141.7475 - @test weight_conversion("ounce", "atomic-mass-unit", 1) == + @test weight_conversion(3, "ounce", "kilogram") == 0.0850485 + @test weight_conversion(3, "ounce", "gram") == 85.0485 + @test weight_conversion(4, "ounce", "milligram") == 113398.0 + @test weight_conversion(4, "ounce", "metric-ton") ≈ 0.000113398 + @test weight_conversion(4, "ounce", "long-ton") == 0.0001116071394054 + @test weight_conversion(4, "ounce", "short-ton") == 0.0001249999988556 + @test weight_conversion(1, "ounce", "pound") == 0.0625000000004599 + @test weight_conversion(2, "ounce", "ounce") == 2.000000000003377 + @test weight_conversion(1, "ounce", "carrat") == 141.7475 + @test weight_conversion(1, "ounce", "atomic-mass-unit") == 1.70724563015874e+25 - @test weight_conversion("carrat", "kilogram", 1) == 0.0002 - @test weight_conversion("carrat", "gram", 4) == 0.8 - @test weight_conversion("carrat", "milligram", 2) == 400.0 - @test weight_conversion("carrat", "metric-ton", 2) ≈ + @test weight_conversion(1, "carrat", "kilogram") == 0.0002 + @test weight_conversion(4, "carrat", "gram") == 0.8 + @test weight_conversion(2, "carrat", "milligram") == 400.0 + @test weight_conversion(2, "carrat", "metric-ton") ≈ 4.0000000000000003e-07 - @test weight_conversion("carrat", "long-ton", 3) == 5.9052438e-07 - @test weight_conversion("carrat", "short-ton", 4) == + @test weight_conversion(3, "carrat", "long-ton") == 5.9052438e-07 + @test weight_conversion(4, "carrat", "short-ton") == 8.818497600000002e-07 - @test weight_conversion("carrat", "pound", 1) == 0.00044092488404000004 - @test weight_conversion("carrat", "ounce", 2) == 0.0141095962892 - @test weight_conversion("carrat", "carrat", 4) == 4.0 - @test weight_conversion("carrat", "atomic-mass-unit", 4) == + @test weight_conversion(1, "carrat", "pound") == 0.00044092488404000004 + @test weight_conversion(2, "carrat", "ounce") == 0.0141095962892 + @test weight_conversion(4, "carrat", "carrat") == 4.0 + @test weight_conversion(4, "carrat", "atomic-mass-unit") == 4.8177093216e+23 - @test weight_conversion("atomic-mass-unit", "kilogram", 4) == + @test weight_conversion(4, "atomic-mass-unit", "kilogram") == 6.642160796e-27 - @test weight_conversion("atomic-mass-unit", "gram", 2) == + @test weight_conversion(2, "atomic-mass-unit", "gram") == 3.321080398e-24 - @test weight_conversion("atomic-mass-unit", "milligram", 2) == + @test weight_conversion(2, "atomic-mass-unit", "milligram") == 3.3210803980000002e-21 - @test weight_conversion("atomic-mass-unit", "metric-ton", 3) ≈ + @test weight_conversion(3, "atomic-mass-unit", "metric-ton") ≈ 4.9816205970000004e-30 - @test weight_conversion("atomic-mass-unit", "long-ton", 3) == + @test weight_conversion(3, "atomic-mass-unit", "long-ton") == 4.9029473573977584e-30 - @test weight_conversion("atomic-mass-unit", "short-ton", 1) == + @test weight_conversion(1, "atomic-mass-unit", "short-ton") == 1.830433719948128e-30 - @test weight_conversion("atomic-mass-unit", "pound", 3) == + @test weight_conversion(3, "atomic-mass-unit", "pound") == 1.0982602420317504e-26 - @test weight_conversion("atomic-mass-unit", "ounce", 2) == + @test weight_conversion(2, "atomic-mass-unit", "ounce") == 1.1714775914938915e-25 - @test weight_conversion("atomic-mass-unit", "carrat", 2) == + @test weight_conversion(2, "atomic-mass-unit", "carrat") == 1.660540199e-23 - @test weight_conversion("atomic-mass-unit", "atomic-mass-unit", 2) == + @test weight_conversion(2, "atomic-mass-unit", "atomic-mass-unit") == 1.999999998903455 + @test_throws ErrorException weight_conversion(1, "kg", "wrong_unit") + @test_throws ErrorException weight_conversion(1, "wrong_unit", "kg") end @testset "Conversions: Temparature Conversions" begin @@ -178,5 +180,7 @@ using TheAlgorithms.Conversions @test length_conversion(5, "in", "m") ≈ 0.127 @test length_conversion(3, "ft", "mm") ≈ 914.4 @test length_conversion(10, "mi", "km") ≈ 16.0934 + @test_throws ErrorException length_conversion(1, "m", "wrong_unit") + @test_throws ErrorException length_conversion(1, "wrong_unit", "m") end end diff --git a/test/data_structures.jl b/test/data_structures.jl index c4c9ac9c..4fa24fc0 100644 --- a/test/data_structures.jl +++ b/test/data_structures.jl @@ -84,6 +84,8 @@ using TheAlgorithms.DataStructure @test LinkedList.return_as_array(list) == [5, 7] @test ismissing(LinkedList.get(list, 3)) == true + @test ismissing(LinkedList.get_node(list, 4)) == true + @test LinkedList.get(list, 2) == 7 LinkedList.clear(list) @test LinkedList.is_empty(list) == true diff --git a/test/graph.jl b/test/graph.jl index ea4e8c53..4b4205a2 100644 --- a/test/graph.jl +++ b/test/graph.jl @@ -41,4 +41,32 @@ using TheAlgorithms.Graph @test_throws ErrorException bellman_ford(negative_edge_cycle, 1) end + + @testset "bfs" begin + graph = [ + [2, 3, 6], + [3, 4], + [4], + [1, 2, 5], + [2], + [1, 5] + ] + + @test bfs(graph, 4) == [4, 1, 2, 5, 3, 6] + @test bfs(graph) == [1, 2, 3, 6, 4, 5] + end + + @testset "dfs" begin + graph = [ + [2, 3, 6], + [3, 4], + [4], + [1, 2, 5], + [2], + [1, 5] + ] + + @test dfs(graph, 6) == [6, 5, 2, 4, 3, 1] + @test dfs(graph) == [1, 6, 5, 3, 4, 2] + end end diff --git a/test/longest_increasing_subsequence.jl b/test/longest_increasing_subsequence.jl index 21c117c8..631ec522 100644 --- a/test/longest_increasing_subsequence.jl +++ b/test/longest_increasing_subsequence.jl @@ -19,6 +19,12 @@ using TheAlgorithms.LongSubSeq # two possible results: @test lis([3, 4, -1, 5, 8, 2, 3, 12, 7, 9, 10], Val(:dp)) in [[-1, 2, 3, 7, 9, 10], [3, 4, 5, 8, 9, 10]] + # Boolean array + @test lis([true, false, false, true], Val(:dp)) == [false, true] + # other Integer subtypes + for T in [UInt128, UInt16, UInt32, UInt64, UInt8, BigInt, Int128, Int16, Int32, Int64, Int8] + @test lis(T[3, 10, 2, 1, 20], Val(:dp)) == T[3, 10, 20] + end end @testset "LIS: Binary Search approach!" begin @@ -39,5 +45,11 @@ using TheAlgorithms.LongSubSeq # two possible results: @test lis([3, 4, -1, 5, 8, 2, 3, 12, 7, 9, 10], Val(:bs)) in [[-1, 2, 3, 7, 9, 10], [3, 4, 5, 8, 9, 10]] + # Boolean array + @test lis([true, false, false, true], Val(:bs)) == [false, true] + # other Integer subtypes + for T in [UInt128, UInt16, UInt32, UInt64, UInt8, BigInt, Int128, Int16, Int32, Int64, Int8] + @test lis(T[3, 10, 2, 1, 20], Val(:bs)) == T[3, 10, 20] + end end end diff --git a/test/math.jl b/test/math.jl index c782e9b8..931d5784 100644 --- a/test/math.jl +++ b/test/math.jl @@ -4,8 +4,8 @@ using TheAlgorithms.Math @test abs_val(-100) == 100 @test abs_val(0) == 0 @test abs(123.1) == 123.1 - @test (-1000 == abs_val(-1000)) == false - @test (1000 == abs_val(1000)) == true + @test abs_val(-1000) == 1000 + @test abs_val(1000) == 1000 @test abs_max([1, 3, 4]) == 4 @test abs_max([-3, 1, 2]) == -3 @@ -59,6 +59,9 @@ using TheAlgorithms.Math @test_throws DomainError area_heron_triangle(-1, -2, 1) @test_throws DomainError area_heron_triangle(1, -2, 1) @test_throws DomainError area_heron_triangle(-1, 2, 1) + @test_throws DomainError area_heron_triangle(1, 1, 3) + @test_throws DomainError area_heron_triangle(1, 3, 1) + @test_throws DomainError area_heron_triangle(3, 1, 1) @test area_parallelogram(10, 20) == 200 @test_throws DomainError area_parallelogram(-1, -2) @@ -139,6 +142,20 @@ using TheAlgorithms.Math @test median([0]) == 0 end + @testset "Math: Binary Length" begin + for bin_length_func in [bin_length, bin_length_long, bin_length_short] + @test bin_length_func(1) == 1 + @test bin_length_func(2) == 2 + @test bin_length_func(3) == 2 + @test bin_length_func(4) == 3 + @test bin_length_func(5) == 3 + @test bin_length_func(12) == 4 + @test bin_length_func(256) == 9 + @test bin_length_func(1024) == 11 + @test_throws DomainError bin_length_func(-1) + end + end + @testset "Math: Catalan Number" begin @test catalan(0) == 1 @test catalan(3) == 5 @@ -239,6 +256,7 @@ using TheAlgorithms.Math @test fib_recursive_memo(6) == [0, 1, 1, 2, 3, 5] @test_throws DomainError fib_recursive_memo(-1) @test fib_iterative(1) == [0] + @test fib_iterative(2) == [0, 1] @test fib_iterative(6) == [0, 1, 1, 2, 3, 5] @test_throws DomainError fib_iterative(-1) end @@ -359,6 +377,15 @@ using TheAlgorithms.Math ) end + @testset "Math: Runge_Kutta Integration" begin + @test runge_kutta_integration((x, y)->1, 0, 0, 1, 3) == ([0.0, 1.0, 2.0, 3.0], [0.0, 1.0, 2.0, 3.0]) + @test begin + x, y = runge_kutta_integration((x, y)->cos(x), 0, 0, 1e-4, π/2) + isapprox(x[end], π/2; rtol=1e-4) && isapprox(y[end], 1; rtol=1e-4) + end + @test_throws DomainError runge_kutta_integration((x, y)->(), 0, 0, 0, 0) + end + @testset "Math: Sum of Arithmetic progression" begin @test sum_ap(1, 1, 10) == 55.0 @test sum_ap(1, 10, 100) == 49600.0 diff --git a/test/matrix.jl b/test/matrix.jl index 7000274a..a3f69729 100644 --- a/test/matrix.jl +++ b/test/matrix.jl @@ -9,6 +9,9 @@ using TheAlgorithms.MatrixAlgo @test determinant(M1) == det(M1) @test round(determinant(M2), digits = 4) == round(det(M2), digits = 4) @test round(determinant(M3), digits = 4) == round(det(M3), digits = 4) + + @test_throws DomainError determinant([1 2]) + @test_throws DomainError determinant([1 2; 3 4; 5 6]) end @testset "Matrix: LU Decompose" begin @@ -79,5 +82,8 @@ using TheAlgorithms.MatrixAlgo Float64[1 0 0; 0 1 0; -0 -0 1], atol = 1e-5, ) + + @test gauss_jordan([0.0 1.0 5.0; 1.0 -2.0 -3.0]) == + [1.0 0.0 7.0; 0.0 1.0 5.0] end end diff --git a/test/project_euler.jl b/test/project_euler.jl index 632f257b..bede8f6e 100644 --- a/test/project_euler.jl +++ b/test/project_euler.jl @@ -83,4 +83,41 @@ using TheAlgorithms.ProjectEuler @test problem_014(Int64(1000000)) == 837799 @test_throws DomainError problem_014(Int64(-1)) end + + @testset "Project Euler: Problem 015" begin + @test problem_015(2, 2) == 6 + @test problem_015(5, 3) == 56 + @test problem_015(20, 20) == 137846528820 + @test_throws DomainError problem_015(0, 5) + @test_throws DomainError problem_015(-3, 0) + end + + @testset "Project Euler: Problem 016" begin + @test problem_016(1, 1) == 1 + @test problem_016(2, 15) == 26 + @test problem_016(2, 1000) == 1366 + @test_throws DomainError problem_016(2, -4) + end + + @testset "Project Euler: Problem 017" begin + @test problem_017() == 21124 + end + + @testset "Project Euler: Problem 018" begin + @test problem_018() == 1074 + end + + @testset "Project Euler: Problem 019" begin + @test problem_019(1901, 2000) == 171 + @test problem_019(1901, 2200) == 515 + @test problem_019(2020, 2023) == 6 + @test_throws DomainError problem_019(-1, 2023) + end + + @testset "Project Euler: Problem 020" begin + @test problem_020(10) == 27 + @test problem_020(37) == 153 + @test problem_020(100) == 648 + @test_throws DomainError problem_020(-1) + end end diff --git a/test/searches.jl b/test/searches.jl index 87174aed..9b1e923a 100644 --- a/test/searches.jl +++ b/test/searches.jl @@ -8,53 +8,68 @@ using TheAlgorithms.Searches unsorted_sample = [124, 53, 21, 163] @test binary_search(sample, 52) == 3:3 @test binary_search(sample, 602) == 6:6 + @test binary_search(sample, 45) == 3:2 @test binary_search(reversed_sample, 52; rev = true) == 5:5 @test binary_search(reversed_sample, 602; rev = true) == 2:2 + @test binary_search(reversed_sample, 45; rev = true) == 6:5 @test_throws ErrorException binary_search(unsorted_sample, 21) # throws an error end @testset "binary_search - second method" begin # Second method used for exponential search arr = [1, 2, 3, 4, 13, 15, 20] # The next three values used are the result of the while-loop inside `exponential search` - @test binary_search(arr, 4, 7, 4) == "Element present at index 4" - @test binary_search(arr, 4, 7, 10) == "Element not present in array" + @test binary_search(arr, 4, 7, 4) == 4 + @test binary_search(arr, 4, 7, 20) == 7 + @test binary_search(arr, 4, 7, 10) == -1 + @test binary_search(arr, 4, 7, 21) == -1 end end @testset "Searches: Linear" begin - array = [1, 3, 4, 7, 8, 11] - linear_search(array, 3) - linear_search(array, 8) - linear_search(array, 12) + array = [1, 30, 4, 70, 8, 11] + @test linear_search(array, 1) == 1 + @test linear_search(array, 30) == 2 + @test linear_search(array, 8) == 5 + @test linear_search(array, 11) == 6 + @test linear_search(array, 12) == -1 + @test linear_search(array, 10) == -1 + @test linear_search(array, 0) == -1 end @testset "Searches: Exponential" begin arr = [1, 2, 3, 4, 13, 15, 20] - x = 4 - n = size(arr)[1] - l = 1 - r = n - @test exponential_search(arr, 1) == "Element present at index 1" - @test exponential_search(arr, x) == "Element present at index 4" - @test exponential_search(arr, 100) == "Element not present in array" + @test exponential_search(arr, 1) == 1 + @test exponential_search(arr, 4) == 4 + @test exponential_search(arr, 20) == 7 + @test exponential_search(arr, 5) == -1 + @test exponential_search(arr, 100) == -1 end @testset "Searches: Interpolation" begin arr = [1, 2, 3, 4, 13, 15, 20] - x = 15 - n = size(arr)[1] l = 1 - r = n + r = size(arr)[1] - interpolation_search(arr, l, r, x) + @test interpolation_search(arr, l, r, 1) == 1 + @test interpolation_search(arr, l, r, 2) == 2 + @test interpolation_search(arr, l, r, 3) == 3 + @test interpolation_search(arr, l, r, 4) == 4 + @test interpolation_search(arr, l, r, 13) == 5 + @test interpolation_search(arr, l, r, 15) == 6 + @test interpolation_search(arr, l, r, 20) == 7 + @test interpolation_search(arr, l, r, 5) == -1 + @test interpolation_search(arr, l, r, 14) == -1 + @test interpolation_search(arr, l, r, 19) == -1 + @test interpolation_search(arr, l, r, 0) == -1 + @test interpolation_search(arr, l, r, 1000) == -1 end @testset "Searches: Jump" begin - arr = [1, 2, 3, 31, 4, 13] - x = 31 - jump = 2 # optimum is sqroot(n) - n = size(arr)[1] - - jump_search(arr, x, jump) + arr = [1, 2, 3, 4, 13, 31] + @test jump_search(arr, 31, 1) == 6 + @test jump_search(arr, 13, 3) == 5 + @test jump_search(arr, 3, 5) == 3 + @test jump_search(arr, 1, 3) == 1 + @test jump_search(arr, 10000, 3) == -1 end end diff --git a/test/sorts.jl b/test/sorts.jl index 9f3f682a..4bbeb275 100644 --- a/test/sorts.jl +++ b/test/sorts.jl @@ -1,22 +1,41 @@ using TheAlgorithms.Sorts @testset "Sorts" begin - sorts = [ - bogo_sort! - bubble_sort! - bucket_sort! - counting_sort! - exchange_sort! - heap_sort! - insertion_sort! - merge_sort! - quick_sort! - selection_sort! - ] + @testset "bogo_sort" begin + x = [3, 1, 4, 2] + bogo_sort!(x) + @test x == [1, 2, 3, 4] + end + + @testset "deterministic sorts" begin + sorts = [ + bubble_sort! + bucket_sort! + counting_sort! + exchange_sort! + heap_sort! + insertion_sort! + merge_sort! + quick_sort! + selection_sort! + ] + + for f in sorts + x = [3, 5, 1, 4, 2] + f(x) + @test x == [1, 2, 3, 4, 5] + + y = [5, 2, 2, 2, 1, 5, 2, 34, 6, 4, 3, 2, 1, 2, 3, 4, 10, 1] + f(y) + @test y == [1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 10, 34] + + z = [] + f(z) + @test z == [] - for f in sorts - x = [3, 5, 1, 4, 2] - f(x) - @test x == [1, 2, 3, 4, 5] + s = [1] + f(s) + @test s == [1] + end end end diff --git a/test/strings.jl b/test/strings.jl index 7c93262b..803fef29 100644 --- a/test/strings.jl +++ b/test/strings.jl @@ -117,6 +117,11 @@ using TheAlgorithms.StringAlgo text = "aaaaaa" pattern = "aaa" @test rabin_karp(text, pattern) == [1, 2, 3, 4] + + @test rabin_karp( + "PHFvbVsfiZlPUjFYGzRcuIYBVPWcMsGiWpaRDERplINOFRnObeHuJbkwQKWlegxlckDRWQNMZOaHUMlwhHnZOcMEBKBfeQRTrIbL", + "ab", + ) == [] end @testset "Strings: Longest common subsequence" begin @test LCS("ABCD", "EFGHIJ") == "" @@ -131,9 +136,11 @@ using TheAlgorithms.StringAlgo @testset "Strings: naive_pattern_search" begin @test naive_pattern_search("ABCDEF", "DEF") == "DEF found at index: 3" - @test naive_pattern_search("Hello world!", "world") == "world found at index: 6" + @test naive_pattern_search("Hello world!", "world") == + "world found at index: 6" - @test naive_pattern_search("Hello world!", "world") == "world found at index: 6" + @test naive_pattern_search("Hello world!", "world") == + "world found at index: 6" @test naive_pattern_search("ABCDEF", "XYZ") == "No matches found" end