This question already has answers here:
Finding all possible combinations of numbers to reach a given sum
(32 answers)
Closed 6 years ago.
Need to create an array whose sum should be equal to expected value.
inp = [1,2,3,4,5,6,7,8,9,10]
sum = 200
output:
out = [10,10,9,1,3,3,3,7,.....] whose sum should be 200
or
out = [10,7,3,....] Repeated values can be used
or
out = [2,3,4,9,2,....]
I tried as,
arr = [5,10,15,20,30]
ee = []
max = 200
while (ee.sum < max) do
ee << arr.sample(1).first
end
ee.pop(2)
val = max - ee.sum
pair = arr.uniq.combination(2).detect { |a, b| a + b == val }
ee << pair
ee.flatten
Is there any effective way to do it.
inp = [1,2,3,4,5,6,7,8,9,10]
sum = 20
inp.length.downto(1).flat_map do |i|
inp.combination(i).to_a # take all subarrays of length `i`
end.select do |a|
a.inject(:+) == sum # select only those summing to `sum`
end
One might take a random element of resulting array.
result = inp.length.downto(1).flat_map do |i|
inp.combination(i).to_a # take all subarrays of length `i`
end.select do |a|
a.inject(:+) == sum # select only those summing to `sum`
end
puts result.length
#⇒ 31
puts result.sample
#⇒ [2, 4, 5, 9]
puts result.sample
#⇒ [1, 2, 3, 6, 8]
...
Please note, that this approach is not efficient for long-length inputs. As well, if any original array’s member might be taken many times, combination above should be changed to permutation, but this solution is too ineffective to be used with permutation.
I found an answer of this question in the following link:
Finding all possible combinations of numbers to reach a given sum
def subset_sum(numbers, target, partial=[])
s = partial.inject 0, :+
#check if the partial sum is equals to target
puts "sum(#{partial})=#{target}" if s == target
return if s >= target #if we reach the number why bother to continue
(0..(numbers.length - 1)).each do |i|
n = numbers[i]
remaining = numbers.drop(i+1)
subset_sum(remaining, target, partial + [n])
end
end
subset_sum([1,2,3,4,5,6,7,8,9,10],20)
Related
I have a following programm
def calc_res(a)
n = a.length
result = 0
for i in 0 .. (n - 1)
for j in i .. (n - 1)
if (a[i] != a[j] && j - i > result) then
result = j - i
end
end
end
return result
end
which return following output
irb(main):013:0> calc_res([4, 6, 2, 2, 6, 6, 4])
=> 5
but it is taking time if array size is too large e.g. [0,1,2,3,.....70000]
can any one suggest me how can I optimize it.
Thanks
If I have understood the problem you are trying to solve (from code)
def calc_res(a)
last_index = a.length - 1
index = 0
while a[index] == a.last do
index = index + 1
break if index == last_index
end
last_index - index
end
It checks items from start if they are equal to items from end, end it moves the index toward the last element. As I understood you search for max length between different elements.
For you problem with [4, 6, 2, 2, 6, 6, 4] it will have one iteration and return 5, for the problem with [1...70000] it will have zero iterations and will return the difference in positions for those two (size of the array - 1)
My understanding is that the problem is to find two unique elements in the array whose distance apart (difference in indices) is maximum, and to return the distance they are apart. I return nil if all elements are the same.
My solution attempts to minimize the numbers of pairs of elements that must be examined before an optimal solution is identified. For the example given in the question only two pairs of elements need be considered.
def calc_res(a)
sz = a.size-1
sz.downto(2).find { |n| (0..sz-n).any? { |i| a[i] != a[i+n] } }
end
a = [4,6,2,2,6,6,4]
calc_res a
#=> 5
If sz = a.size-1, sz is the greatest possible distance two elements can be apart. If, for example, a = [1,2,3,4], sz = 3, which is the number of positions 1 and 4 are apart.
For a, sz = a.size-1 #=> 6. I first determine if any pair of elements that are n = sz positions apart are unique. [a[0], a[6]] #=> [4,4] is the only pair of elements 6 positions apart. Since they are not unique I reduce n by one (to 5) and examine all pairs of elements n positions apart, looking for one whose elements are unique. There are two pairs 5 positions apart: [a[0], a[5]] #=> [4,6] and [a[1], a[6]] #=> [6,4]. Both of these meet the test, so we are finished, and return n #=> 5. In fact we are finished after testing the first of these two pairs. Had neither these pairs contained unique values n would have been reduced by 1 to 4 and the three pairs [a[0], a[4]] #=> [4,6], [a[1], a[5]] #=> [6,6] and [a[2], a[6]] #=> [2,6] would have been searched for one with unique values, and so on.
See Integer#downto, Enumerable#find and Enumerable#any?.
A more rubyesque versions include:
def calc_res(a)
last = a.last
idx = a.find_index {|e| e != last }&.+(1) || a.size
a.size - idx
end
def calc_res(a)
last = a.last
a.size - a.each.with_index(1).detect(->{[a.size]}) {|e,_| e != last }.last
end
def calc_res(a)
last = a.last
a.reduce(a.size) do |memo, e|
return memo unless e == last
memo -= 1
end
end
def calc_res(a)
return 0 if b = a.uniq and b.size == 1
a.size - a.index(b[-1]).+(1)
end
def third_greatest(nums)
idx = 0
arr = []
i = 1
largest = 0
while idx < nums.length
while i < nums.length
if nums[idx] > nums [i]
largest = nums[idx]
else
largest = nums[idx]
end
i += 1
end
arr.push(largest)
idx += 1
i += idx
end
return arr[2]
end
puts(third_greatest([4, 3, 2, 1]) == 2)
#should equal true
I'm trying to get the third largest number out of the array but I keep getting four for any value of the array that returns data.
Any help would be great!
Here is an easier solution for finding the third greatest number in an array:
def third_greatest(nums)
nums.sort!
nums[-3]
end
third_greatest([4, 3, 2, 1])
=> 2
puts(third_greatest([4, 3, 2, 1]) == 2)
=> true
at the end of the first time to the loop, i will be nums.length.
afterwards you increase i with idx so it is now bigger than nums.length.
In the next loops you will never enter the inner loop again, so the largest is never updated anymore.
That's why you always get largest in the result.
to fix it do something like :
end
arr.push(largest)
idx += 1
i = idx + 1
end
so that i is reset to one higher than idx.
But the real solution is to leverage the rich standard library as Alex suggests.
Recent versions of Enumerable#max have allowed a parameter:
(0..9).to_a.max(3).last #=> 7
max(n) returns the three largest values, in decreasing magnitude. This could be expected to be more efficient than sort (unless n == arr.size, of course). Related Enumerable methods (max_by, min, min_by) also have this functionality.
Other than hardcoding or using the Math module, Is there any way I can find divisors of 60 in Ruby on Rails. Any helper methods/regular expression that I can make use of? Thanks for your help.
One of the easiest ways to achieve this would be to create a list of numbers between 1 and 60, and then only select the ones that divide 60 with no remainder.
To expand on SteveTurczyn's answer, we can do:
(1..60).select { |n| 60 % n == 0 }
The (1..60) part creates an enumerator (which in this case we can think of as an array of the numbers between 1 and 60).
Then you want to take this array, and select only the elements are divisors of 60.
We can use the modulus operator %, which gives us the remainder left over when we divide a number by another (e.g., 5 % 2 returns 1). Of course, if there is no remainder, then we know that the number divided cleanly, and is therefore a divisor of that number (i.e., if a % b == 0, then b is a divisor of a).
So what we want to do, is use the above as a criteria for selecting elements out of the array of numbers between 1 and 60, which we are able to do with the Array#select method.
If we have something, like an array (technically, I think, an Enumerable), we can use #select and a block to pull out only the elements that satisfy whatever criteria we specify in the block.
The { |n| 60 % n == 0 } is the block we are passing to #select, which will return true whenever 60 % n is 0 (each n is an element from the array of numbers 1 through 60). Array#select only returns the elements in the array for which the block evaluates to true- which is how SteveTurczyn's solution works.
This will give you the array of divisors
(1..60).select { |n| 60 % n == 0}
=> [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60]
For small numbers it's okay to use the brute force search, but for large numbers this approach doesn't suite. You can speed up your method significantly by selecting divisors as pairs.
Some examples with benchmarks:
require 'benchmark'
n = 10_000_000
def brute_force(n)
(1..n).select { |i| n % i == 0 }
end
def faster_way(n)
(1..Math.sqrt(n)).each_with_object([]) { |i, arr| (n % i).zero? && arr << i && n/i != i && arr << n/i }
end
Benchmark.bm do |x|
x.report { brute_force(n) }
x.report { faster_way(n) }
end
# Benchmark output
user system total real
0.799491 0.001417 0.800908 ( 0.802341)
0.000580 0.000002 0.000582 ( 0.000581)
As you can see the second approach is 1376 times faster for n = 10_000_000.
I'm currently practicing programming problems and out of interest, I'm trying a few Codility exercises in Lua. I've been stuck on the Passing Cars problem for a while.
Problem:
A non-empty zero-indexed array A consisting of N integers is given. The consecutive elements of array A represent consecutive cars on a road.
Array A contains only 0s and/or 1s:
0 represents a car traveling east,
1 represents a car traveling west.
The goal is to count passing cars. We say that a pair of cars (P, Q), where 0 ≤ P < Q < N, is passing when P is traveling to the east and Q is traveling to the west.
For example, consider array A such that:
A[0] = 0
A[1] = 1
A[2] = 0
A[3] = 1
A[4] = 1
We have five pairs of passing cars: (0, 1), (0, 3), (0, 4), (2, 3), (2, 4).
Write a function:
function solution(A)
that, given a non-empty zero-indexed array A of N integers, returns the number of pairs of passing cars.
The function should return −1 if the number of pairs of passing cars exceeds 1,000,000,000.
For example, given:
A[0] = 0
A[1] = 1
A[2] = 0
A[3] = 1
A[4] = 1
the function should return 5, as explained above.
Assume that:
N is an integer within the range [1..100,000];
each element of array A is an integer that can have one of the following values: 0, 1.
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
My attempt in Lua keeps failing but I can't seem to find the issue.
local function solution(A)
local zeroes = 0
local pairs = 0
for i = 1, #A do
if A[i] == 0 then
zeroes = zeroes + 1
else
pairs = pairs + zeroes
if pairs > 1e9 then
return -1
end
end
end
return pairs
end
In terms of time-space complexity constraints, I think it should pass so I can't seem to find the issue. What am I doing wrong? Any advice or tips to make my code more efficient would be appreciated.
FYI: I keep getting a result of 2 when the desired example result is 5.
The problem statement says A is 0-based so if we ignore the first and start at 1, the output would be 2 instead of 5. 0-based tables should be avoided in Lua, they go against convention and will lead to a lot of off-by one errors: for i=1,#A do will not do what you want.
function solution1based(A)
local zeroes = 0
local pairs = 0
for i = 1, #A do
if A[i] == 0 then
zeroes = zeroes + 1
else
pairs = pairs + zeroes
if pairs > 1e9 then
return -1
end
end
end
return pairs
end
print(solution1based{0, 1, 0, 1, 1}) -- prints 5 as you wanted
function solution0based(A)
local zeroes = 0
local pairs = 0
for i = 0, #A do
if A[i] == 0 then
zeroes = zeroes + 1
else
pairs = pairs + zeroes
if pairs > 1e9 then
return -1
end
end
end
return pairs
end
print(solution0based{[0]=0, [1]=1, [2]=0, [3]=1, [4]=1}) -- prints 5
Noob to Ruby here. Working through some exercises and have hit a wall.
Exercise: Calculate the letter grade of a series of grades
Create a method get_grade that accepts an Array of test scores. Each score in the array should be between 0 and 100, where 100 is the max score.
Compute the average score and return the letter grade as a String, i.e., 'A', 'B', 'C', 'D', 'E', or 'F'.
I keep returning the error:
avg.rb:1: syntax error, unexpected tLBRACK, expecting ')'
def get_grade([100,90,80])
^
avg.rb:1: syntax error, unexpected ')', expecting $end
Here's what I have so far. I'd like to stick with the methods below or .join as I'm trying to work with the methods we're learning in class. So sum, inject, etc won't necessarily be helpful. And I apologize in advance for the specificity of the request :) I'm sure there's a way better way that is way less code, but I'm just trying to learn it this way to start.
def get_grade([100,90,80])
get_grade = (array[0] + array[1] + array[2]).to_i / array.length.to_i
case get_grade
when 90..100
"A"
when 80..90
"B"
when 70..80
"C"
when 60..70
"D"
when 0..60
"F"
else
"Error"
end
end
puts get_grade([100,90,80])
You can't just randomly dump an array literal like [100,90,80] into the parameter list of a function definition. Judging by the function body, I think you meant to accept a single parameter array:
def get_grade(array)
grade = (array[0].to_i + array[1].to_i + array[2].to_i) / array.length
case grade
# unchanged
end
end
A terse replacement of the big case statement, for fun:
def letter_grade( score ) # assumes that score is between 0 and 100 (not 0-1)
%w[F F F F F F D C B A][ (score/10.0).floor ] || 'A' # handles grades >=100
end
Or, for more granularity:
def letter_grade( score ) # score is between 0 and 100 (not 0-1)
grades = %w[F F F F F F F F F F F F F F F F F F D- D D+ C- C C+ B- B B+ A- A A+ A+]
grades[ (3.0*score/10).floor ]
end
Thanks for the help today! Here's what I ended up doing to make it work with more than just 3 arguments. I used an Array#each method. I imagine there's a more elegant solution out there, but it worked! Worked on this since 10:00 AM, greatly appreciate the help!
def get_grade(array)
sum = 0
array.each do |element|
sum += element
end
average = sum / array.length
if average >= 90
grade = "A"
elsif average >= 80
grade = "B"
elsif average >= 70
grade = "C"
elsif average >= 60
grade = "D"
elsif average >= 0
grade = "F"
else
"Error"
end
end
puts get_grade([70,80,80,90,100])
puts get_grade([100,80,90,11,20])
puts get_grade([30,20,10,60,75])
Remember that the max score is 100 (and it can be assumed that the min is 0).
def get_grade(array)
sum = 0
array.each do |x|
sum += x
end
average = sum / array.length
if average > 100
print "Grades must be no more than 100!"
elsif average >= 90
grade = "A"
elsif average >= 80
grade = "B"
elsif average >= 70
grade = "C"
elsif average >= 60
grade = "D"
elsif average >=0
grade = "F"
else
print "Grades must be no less than 0!"
end
grade
end
puts get_grade([100,90,80]) == "A"
puts get_grade([98,90,80]) == "B"
puts get_grade([80,80,80]) == "B"
puts get_grade([55,45,35]) == "F"
puts get_grade([101,100,104])
puts get_grade([-2,-3,-4])
Added a proc so that even if a user enters a score over 100 it won't be calculated into the average.
Also refactored the switch statements to one line each. Let me know if this helps. Good luck.
def get_grade array
scores_under_100 = Proc.new {|score| score <= 100 && score > 0}
scores = array.select(&scores_under_100)
average = scores.inject(:+) / scores.size
case average
when 90..100 then puts "A."
when 80..89 then puts "B."
when 70..79 then puts "C."
when 60..69 then puts "D."
else puts "F."
end
end
puts get_grade([100, 100, 90, 67, 85, 200, 290, 299, 299])