Recursion and order of statements execution - ruby

This question deals with how the statements and those involving recursion are executed, and in what order Ruby will handle the,. Specifically, as I've been learning online, I have found that Ruby does not follow Last in first out convention in a stack form of memory-management, but rather has a garbage collector. I have numbered questions at the bottom after all the code. I hope I have made everything clear, but please let me know what parts of the question may need improvement. Thank you.
def append(array, n)
return array if n < 0 #base case, how we end this thing
array << n*2 #Line No. 1
append(array, n - 1) #Line No. 2
array << n*2 #Line No. 3
end
append( [], 3)
#output [6,4,2,0,0,2,4,6]
The two lines below give the output of [6,4,2,0]
array << n*2 #Line No. 1
append(array, n - 1) #Line No. 2
When the order of the two statements are reversed the output is [0,2,4,6]
append(array, n - 1) #Line No. 2
array << n*2 #Line No. 3
In the original append method (top section of code), why does ruby stop to compute at the first recursive call, continue on to line 3, and then do the second recursive call, then concatenate the output of both recursions?
If line 2 and line 3 were the only part of the recursion the output would be[0,2,4,6], in ascending order. What is the convention that Ruby uses in its execution? Why does this code not give the output [6,4,2,0], since the n-1 is being called before array << n*2?
Is there a proper definition or programming theory as to how these recursive calls are handled?

Ruby is doing nothing unusual here, any more than any other "typical" computer language.
In the original append method (top section of code), why does ruby stop to compute at the first recursive call, continue on to line 3, and then do the second recursive call, then concatenate the output of both recursions?
I don't see any evidence for this. The first half of the output 6,4,2,0 is from Line 1. The second half 0,2,4,6 is from Line 3. Note that the first time it falls through to Line 3 is when n==0. So the next value after 6,4,2,0 is 0, then 2, 4, and finally 6. It pops out of the call stack, LIFO, just like any other computer language.
If line 2 and line 3 were the only part of the recursion the output would be[0,2,4,6], in ascending order. What is the convention that Ruby uses in its execution? Why does this code not give the output [6,4,2,0], since the n-1 is being called before array << n*2?
Because it has to call append 4 times before it returns to fall through to Line 3. By this time, n=0 which is why 0 is still first in this case.
Is there a proper definition or programming theory as to how these recursive calls are handled?
It's just LIFO. Give it some more thought.
If you're still not convinced, here is C++ code that prints the exact same sequence:
#include <iostream>
#include <list>
using namespace std;
list<int>& append( list<int> &array, int n )
{
if( n < 0 ) return array;
array.push_back(n*2);
append( array, n-1 );
array.push_back(n*2);
return array;
}
int main()
{
list<int> array;
append( array, 3 );
for( int& x : array ) cout << x << ' ';
cout << endl;
}

Related

How can I go on about getting the right output to the user in this recursive function in ruby?

def fibs_rec (n,barray = [])
return 1 if n == 1 || n == 0
a = fibs_rec(n-1,barray) + fibs_rec(n-2,barray)
barray << a
return a
end
for description, This function takes an argument n and prints the first n numbers in the fibonacci sequence but, it isnt quite working as it is supposed to be.
I want it to print the first n fibonacci numbers without any repetitions.
for example if n is 4, output should be 0,1,1,2 instead of 0,1,0,1,1,0,1,1,2. That basically happens when i print barray inside the recursion because i dont have any other option and for that sake i have removed that line.
The thing is I cant remove the return a and replace it with return barray. Not only will that mess up the functionality, fibs_rec is expecting to get a number back to perform the calculations and that wont work when I will return barray just to display the output to the user and neither can I print array because that will keep outputting the new data alongside with the old data and I just want it to be a one single clean output of the whole fibonacci numbers.
For the first question, you cannot remove return a and replace with return barray because
fibs_rec(n-1, barray) + fibs_rec(n-2, barray) will return an array instead of integer.
def fibs_rec(n, barray = [])
return 1 if n == 1 || n == 0
a = fibs_rec(n-1, barray) + fibs_rec(n-2, barray) # a = [2] + [2] wrong!
barray << a
return barray # return an array[]
end
Moreover, according to your problem description, it would be better not to write in a recursive program but if you are required to do a recursive program, I would suggest you that the fibs_rec function you wrote isn't trying to print the pattern but trying to find the fibo number at position n. For example:
# According to your program, you will miss the first 0 of fibonacci sequence
# (0,) 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……..
fibs_rec(0) # return: 1
fibs_rec(1) # return: 1
fibs_rec(2) # return: 2
fibs_rec(3) # return: 3
fibs_rec(4) # return: 5
. . .
If you want to print out the sequence using recursive function fibs_rec, you will need to create another function to call it from 0 to n.
There are a lot of good resources explaining about Fibonacci and recursive out there. You do not quite understand how recursive works. Try to understand it first. Good luck!

The integers in the array are either entirely odd or entirely even except for a single integer

You are given an array (which will have a length of at least three, but could be very large) containing integers. The array is either entirely comprised of odd integers or entirely comprised of even integers except for a single integer N. Write a method that takes the array as an argument and returns this outlier N.
This is my code so far, which doesn't seem to work:
arr = [160, 3, 1719, 19, 11, 13, -21]
n = arr.length
def getOddOccurrence(arr, arr_size)
for i in range(0, arr_size)
count = 0
for j in range(0, arr_size)
if arr[i] == arr[j]
count += 1
end
if(count % 2 != 0)
return arr[i]
end
end
end
return -1
end
print getOddOccurrence(arr, n)
What change do I need with this code?
Here is a simple way to do it
arr = [160, 3, 1719, 19, 11, 13, -21]
arr.group_by(&:odd?).values.sort_by(&:count)[0][0]
# => 160
group_by(&:odd?) Will make 2 hashes for odd and even numbers
values Will grab the values of the hash. 2 arrays, for even and odd
sort_by(&:count) Sort arrays, one with less values will be first
[0][0] Grab the first number of the first array
Here's a solution that is arcane (ugly), but relatively straightforward. It takes O(arr.size) time and uses O(1) additional storage. It also "short-circuits" as soon as it finds the outlier.
Here's the basic idea. Even numbers have zero for the least significant bit, and odd numbers have one, so if you XOR an adjacent pair of numbers the least significant bit will be one only if they lack parity. The first time that happens after the first pair, you've found the outlier. If it happens with the first pair, you need to check the second pairing. If that yields a zero, the first value was the outlier, otherwise it was the second.
def getOddOccurrence(arr)
arr.each_index do |i|
return arr[i == 1 && (arr[i] ^ arr[i + 1]) & 1 == 0 ? 0 : i] if i > 0 && (arr[i] ^ arr[i - 1]) & 1 == 1
end
end
And here's the same concept in a slightly more Rubyish manner:
def getOddOccurrence(arr)
arr.each_cons(3) { |x,y,z| return ((y ^ z) & 1 == 1 ? y : x) if (x ^ y) & 1 == 1 }
arr[-1]
end
If you prefer looking at subsets of 2, make a one-off check of the first 3 values and then work with cons(2) subsets. You can also replace bit-testing with a check for consistency on evenness (or oddness) to improve readability:
def getOddOccurrence(arr)
return arr[0] if (arr[0].odd? ^ arr[1].odd?) && !(arr[1].odd? ^ arr[2].odd?)
arr.each_cons(2) { |x,y| return y if (x.odd? ^ y.odd?)}
end
I finally had a few spare minutes to throw together a benchmark:
require 'benchmark/ips'
def getOddOccurrence_cons3(arr)
arr.each_cons(3) { |x,y,z| return ((y ^ z) & 1 == 1 ? y : x) if (x ^ y) & 1 == 1 }
arr[-1]
end
def getOddOccurrence_cons2(arr)
return arr[0] if (arr[0].odd? ^ arr[1].odd?) && !(arr[1].odd? ^ arr[2].odd?)
arr.each_cons(2) { |x,y| return y if (x.odd? ^ y.odd?) }
end
def getOddOccurrence_cons2_bits(arr)
return arr[0] if ((arr[0] ^ arr[1]) & 1 == 1) && ((arr[1] ^ arr[2]) & 1 == 0)
arr.each_cons(2) { |x,y| return y if (x ^ y) & 1 == 1 }
end
def getOddOccurrence_find(arr)
arr.first(3).count(&:odd?) > 1 ? arr.find(&:even?) : arr.find(&:odd?)
end
def getOddOccurrence_find_bits(arr)
arr.first(3).sum {|x| x & 1} > 1 ? arr.find { |x| (x & 1) == 0 } : arr.find { |x| (x & 1) == 1 }
end
def find_outlier(ary)
# fetch first 3 numbers and determine what kind of array
# are we dealing with here, mostly odd or mostly even?
mostly_odd = ary.take(3).count(&:odd?) > 1
# then just go and find the outlier element
if mostly_odd
ary.find(&:even?)
else
ary.find(&:odd?)
end
end
arr = Array.new(10_000) { |i| i * 2 }.shuffle << 5
Benchmark.ips do |b|
b.report('cons3 bits:') { getOddOccurrence_cons3(arr) }
b.report('cons2 bits:') { getOddOccurrence_cons2_bits(arr) }
b.report('cons2 even/odd:') { getOddOccurrence_cons2(arr) }
b.report('find even/odd:') { getOddOccurrence_find(arr) }
b.report('find bits:') { getOddOccurrence_find_bits(arr) }
b.report('find sergio:') { find_outlier(arr) }
b.compare!
end
As you can see, I put an odd value at the end of an even array to maximize the searching required.
And the winner is...
Warming up --------------------------------------
cons3 bits: 128.000 i/100ms
cons2 bits: 127.000 i/100ms
cons2 even/odd: 103.000 i/100ms
find even/odd: 216.000 i/100ms
find bits: 217.000 i/100ms
find sergio: 231.000 i/100ms
Calculating -------------------------------------
cons3 bits: 1.251k (± 4.9%) i/s - 6.272k in 5.026355s
cons2 bits: 1.294k (± 3.4%) i/s - 6.477k in 5.010802s
cons2 even/odd: 1.038k (± 4.4%) i/s - 5.253k in 5.070617s
find even/odd: 2.284k (± 4.2%) i/s - 11.448k in 5.022831s
find bits: 2.165k (± 5.3%) i/s - 10.850k in 5.027801s
find sergio: 2.277k (± 3.3%) i/s - 11.550k in 5.078381s
Comparison:
find even/odd:: 2283.6 i/s
find sergio:: 2276.9 i/s - same-ish: difference falls within error
find bits:: 2164.6 i/s - same-ish: difference falls within error
cons2 bits:: 1294.2 i/s - 1.76x slower
cons3 bits:: 1251.1 i/s - 1.83x slower
cons2 even/odd:: 1038.1 i/s - 2.20x slower
...the one-liner from Sagar Pandyar's comment!
The find-based approach clearly beats each_cons. Using Ruby's odd/even methods vs binary operations appears to have only a minor impact. Interestingly, using .each_cons(3) rather than .each_cons(2) has very little relative impact as well, although both are clearly dominated by Sagar & Sergio's approach.
Welcome to Stack Overflow!
Since you're new, let me start by saying that asking for solutions here is generally not well received. This isn't a place to have other people do your work for you, so you should check out https://stackoverflow.com/help/how-to-ask to learn about what makes a good question for the future.
That said, rather than give you a solution, let me see if I can aid your understanding of what seems to be tripping you up. I'm going to ignore a lot of the "ruby-isms" that can shorten things a lot, since they are nice but ultimately it seems like you might still need an understanding of the underlying approach rather than shortcuts, since that's what helps you program better in the long run.
if arr[i] == arr[j]
count +=1
end
The above code is looking for two numbers in the array that are equal. That means count is never going to be incremented unless your array contains two of the same value, which is not what you want from your description of the task. Additionally, this problem really doesn't need you to compare two numbers in the array. You just need to determine whether each number is odd or even and find the outlier.
The easiest (and possibly most common) programming way of determining whether a number is odd is by using the modulo operator (%). You used this in checking your count variable, which again really isn't what you need. Instead, you should be using it against each entry in the array. So for some integer value n, n % 2 will be 0 if it's an even number, or 1 if it's an odd number. It seems like you somewhat understood this, but use this against each number in the array to determine whether it is even or odd instead of on the count variable, and then you can act on that information for each number.
Once you've got it so that you're determining whether each number in the array is even or odd, you need a way to track whether you're searching for an odd or even number. The simplest way to do this would be to keep track of even/odd count in a variable, but have one variable for even count and a separate one for odd count. So when you encounter an even number, you can add 1 to the even count, and similarly for odd numbers but to the odd count. That way you know the type you are looking for (even or odd) is whichever count equals 1 after you finish going through the array. This means that these variables should be outside of the loop that looks through the array, since you don't want them to reset for each number in the array, and you're probably going to want to look at them after the loop also.
Once you've determined whether you're looking for odd or even, you can go through the array a second time (not a nested loop, but a second one after the first one) and return the odd or even number from the array as appropriate. There are ways to do it without a second loop, but I'm trying to keep it straight forward.
Hopefully this helps you come up with your own solution so you can learn from solving the problem. If you get it working with my basic layout, there are several ways that you can make it better in terms of performance or just amount of code (such as not using a second loop). Happy to clarify if you need.
Happy coding!
Here is a linear-time constant-memory algorithm
def find_outlier(ary)
# fetch first 3 numbers and determine what kind of array
# are we dealing with here, mostly odd or mostly even?
mostly_odd = ary.take(3).count(&:odd?) > 1
# then just go and find the outlier element
if mostly_odd
ary.find(&:even?)
else
ary.find(&:odd?)
end
end
ary = [161, 3, 1719, 19, 11, 160, 13, -21]
find_outlier(ary) # => 160

How do I interpret this pseudocode in Ruby?

I don't quite understand how to "initialize a multidimensional array to equal 1" as the initial for loops seem to suggest here. I haven't learned to properly read pseudocode, and I don't fully understand how this program works.
function countRoutes(m,n)
grid ← array[m + 1][n + 1]
for i = 0 to m do
grid[i][0] ← 1
end for
for j = 0 to n do
grid[0][j] ← 1
end for
for i = 1 to m do
for j = 1 to n do
grid[i][j] ← grid[i − 1][j] + grid[i][j − 1]
end for
end for
return grid[m][n]
end function
Thanks for your help!
This isn't hard to translate.. Ruby uses = instead of left arrow for assignment, and def instead of function to define a subroutine (which it calls a method instead of a function), but that's about it. Let's go through it.
function countRoutes(m,n)
That's beginning a function definition. In Ruby we use a method instead, and the keyword to define such a thing is def. It's also convention in Ruby to use snake_case for multiword names instead of camelCase:
def count_routes(m, n)
Now to create the grid:
grid ← array[m + 1][n + 1]
Ruby arrays are dynamic, so you don't normally need to specify the size at creation time. But that also means you don't get initialization or two-dimensionality for free. So what we have to do here is create an array of m+1 arrays, each of which can be empty (we don't need to specify that the sub-arrays need to hold n+1 items). Ruby's Array constructor has a way to do just that:
grid = Array.new(m+1) do [] end
Now the initialization. Ruby technically has for loops, but nobody uses them. Instead, we use iterator methods. For counting loops, there's a method on integers called times. But the pseudocode counts from 0 through m inclusive; times also starts at 0, but only counts up to one less than the invocant (so that way when you call 3.times, the loop really does execute "three times", not four). In this case, that means to get the behavior of the pseudocode, we need to call times on m+1 instead of m:
(m+1).times do |i|
grid[i][0] = 1
end
As an aside, we could also have done that part of the initialization inside the original array creation:
grid = Array.new(m+1) do [1] end
Anyway, the second loop, which would be more awkward to incorporate into the original creation, works the same as the first. Ruby will happily extend an array to assign to not-yet-existent elements, so the fact that we didn't initialize the subarrays is not a problem:
(n+1).times do |j|
grid[0][j] = 1
end
For the nested loops, the pseudocode is no longer counting from 0, but from 1. Counting from 1 through m is the same number of loop iterations as counting from 0 through m-1, so the simplest approach is to let times use its natural values, but adjust the indexes in the assignment statement inside the loop. That is, where the pseudocode starts counting i from 1 and references i-1 and i, the Ruby code starts counting i from 0 and references i and i+1 instead.
m.times do |i|
n.times do |j|
grid[i+1][j+1] = grid[i][j+1] + grid[i+1][j]
end
end
And the return statement works the same, although in Ruby you can leave it off:
return grid[m][n]
end
Putting it all together, you get this:
def count_routes(m, n)
grid = Array.new(m+1) do [1] end
(n+1).times do |j|
grid[0][j] = 1
end
m.times do |i|
n.times do |j|
grid[i+1][j+1] = grid[i][j+1] + grid[i+1][j]
end
end
return grid[m][n]
end
The notation grid[i][j] ← something means assigning something to the element of grid taking place on i-th line in j-th position. So the first two loops here suggest setting all values of the first column and the first row of the grid (correspondingly, the first and the second loops) to 1.

Ruby - Hackerrank Puzzle - Save the Prisoner

I'm having a hard time understanding how to solve this problem without causing memory allocation problems. I'm pretty sure my logic is sound but unfortunately that doesn't seem to be good enough. Does anyone have any recommendations for this so I can understand how to write the code more efficiently?
Here's the problem:
Sample Input:
1
5 2 1
Sample Output
2
There are N = 5 prisoners and M = 2 sweets. Distribution starts at ID number S = 1, so prisoner 1 gets the first sweet and prisoner 2 gets the second (last) sweet. Thus, we must warn prisoner about the poison, so we print 2 on a new line.
# Enter your code here. Read input from STDIN. Print output to STDOUT
n = gets.strip.to_i
n.times do
arr = gets.strip.split(" ").map { |s| s.to_i}
prisoners = arr[0].to_i
sweets = arr[1].to_i
position = arr[2].to_i
prisoners_array = (1..prisoners).map { |p| p.to_i}
starting_position = prisoners_array[position - 1]
end_position = prisoners_array.size
awesome_array = (starting_position..end_position).map { |p| p.to_i}
awesomer_array = (prisoners_array[0]...starting_position).map { |p| p.to_i}
awesomest_array = awesome_array + awesomer_array
warning = 0
if sweets > prisoners
sweets = sweets % prisoners
end
for i in awesomest_array
warning += 1
if warning === sweets
puts prisoners_array[i - 1]
end
end
end
This appears to be the exercise in question. The key here is managing your use of modulo (which calculates a 0-indexed position) with the problem (which uses 1-indexed positions).
In the example case, we have 5 people (n) and want to iterate 2 positions (m) over them starting from person #1 (s). Person #1 is index position 0 which we calculate by subtracting one from s. We must also subtract one from the distance travelled t because getting to the starting position is considered the first move. So we have s+m-2.
By taking this resultant number, modulo % the total number of people, we will have calculated the 0-indexed position that we end up at. We'll need to add one back to this number to convert back to a 1-indexed system.
While it's okay to take a long-form approach to working exercise problems out (such as by populating arrays and actually iterating over them), this problem can also be solved as follows:
# Enter your code here. Read input from STDIN. Print output to STDOUT
gets.strip.to_i.times do
# n - number of prisoners
# m - number of sweets
# s - starting id
n, m, s = gets.split.map &:to_i
puts ((m+s-2) % n) + 1
end
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int t;
cin>>t;
for(int q=0;q<t;q++)
{
long long int n,m,s;
cin>>n>>m>>s;
while(s!=m)
{
if(s==n)s=0;
s++;
}
cout<<s;
//exit(0);
}
return 0;
}

How do I properly use a for loop in Ruby?

I'm trying to improve my Ruby skills using the Project Euler series of questions and I'm wondering why this code does not work for this question: "Even Fibonacci numbers, Problem 2"
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
My code:
def fibo(n)
first, second, sequence = 0,1,[]
for e in n
first, second = second, first + second
sequence << e if e%2 == 0
end
sequence.inject(:+)
end
puts fibo(4000000)
Any help would be appreciated!
In the line:
for e in n
4,000,000 is being substituted for n, so you are saying:
for e in 4000000
which is not a valid statement - you cannot iterate on an integer.
If you would like to iterate through all the values from 0 to n, try:
for e in (0..n)
This iterates through the values in the range 0 to n.
However, there is a deeper problem here. It looks as though you want to iterate up to the value 4000000, but instead your code would iterate through the first 4000000 Fibonacci numbers, which is much more than you want. You may want to consider saying:
while second <= 4000000
I suggest you check out Ruby Koans if you're starting out with Ruby. It's a fun way of getting used to the ways of the language.
That said your code is not calculating Fibonacci correctly, it's not summing the Fibonacci numbers and also has some other errors (for e in n is not valid because n is not an Enumerator type). Fix it like this:
def fibo(n)
first, second, sum = 0, 1, 0
loop do
first, second = second, first + second
sum += second if second%2 == 0
break if second >= n
end
sum
end

Resources