Coding Challenge 2 - algorithm

Find the element in an array which has consecutive plus or minus 1. I can achieve in O(n) time by doing a linear search. Is there any efficient way to achieve in less than O(n) time.
What I mean by plus or minus 1 is 2 consecutive number in an array will have either -1 or 1 as the difference
For example sample array inputs
Consecutive element have +1 of difference
arr = [1,2,3,4,5]
Consecutive elements have -1 of difference
arr = [ -1,-2, -3, -4 , -5, ]
Elements have either +1 or -1 of difference
arr = [-5,-4,-3,-4, -3,-2,-1,0,1,2,3,4,3,2,1]
Note: Array is unsorted
Example
arr = [-5,-4,-3,-4,-3,-2,-1,0,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1,0,-1,-2,-3,-4,-3,-2,-1]
while i <= arr.length do
if num == a[i]
puts "found"
break
end
i += 1
end
2nd approach which in my mind is instead of starting from 0 index I have done some custom logic
num = gets.to_i
i = 0
if (num < 0 && arr[0] < 0) || (num > 0 && arr[0] < 0)
i = (num + arr[0].abs).abs
elsif num < 0 && arr[0] > 0
i = num.abs + arr[0]
elsif num > 0 && arr[0] > 0
i = (num > arr[0] ? (num - arr[0]) : (arr[0] - num))
end
while i <= arr.length do
if num == a[i]
puts "found"
break
end
i += 1
end

As Nico Schertler said, O(n) is the best you can do. This is a find operation, and find operations on unsorted data are always O(n), because in the worst case they must check every element. This would be different if your data were sorted. See binary search.
Note also that your example code does not do what you're asking - it simply finds some number num in the list. Your example code is equivalent to:
arr.find { |i| i == num }
What you appear to be asking for is
arr.find { |i| i == num - 1 or i == num + 1 }

Related

Comparison of Integer with nil failed (ArgumentError) while solving Insertion Sort with Ruby

Below is the updated code:
def insertion_sort(list)
num = list.length
for i in (0..(num-2))
if list[i] > list[i+1] && i == 0
list[i], list[i+1] = list[i+1], list[i]
i+=1
elsif list[i] == list[i+1]
i+=1
elsif list[i] > list[i+1] && i > 0
len = (list[0..(i+1)].length)
list2 = list[0..(i+1)]
list = list - list2
count = 0
while count <= len+1
if list2[len-1] < list2[len-2]
list2[len-2],list2[len-1]= list2[len-1],list2[len-2]
elsif list2[len-1] == list2[len-2]
count+=1
len-=len
else
count+=1
len-=1
end
end
list = list2 + list
end
end
list
end
p insertion_sort([2,1,4,8,7,3,100,99,8])
p insertion_sort([2,1,4,8,8,7,3,100,99])
p insertion_sort([3790,780,780,1,55])
Summary:
code works if two identical integers are right next to each other :[2,1,4,8,8,7,3,100,99] and the array size > 5.
if the two identical integer are at random positions: [2,1,4,8,7,3,100,99,8]. Below error would occur
aaa.rb:4:in `>': comparison of Integer with nil failed (ArgumentError)
with Line 4 code being: if list[i] > list[i+1] && i == 0
To solve 1. I changed the while loop to "while count <= len+1",
so when array size is smaller than 5 the code would work. But not when identical integers are at random positions.
Does anyone know how to solve this?
Thanks in advance!
Thanks for the clarification in the comments. I see the problem now.
In the swap algorithm here
elsif list[i] > list[i+1] && i > 0
len = (list[0..(i+1)].length)
list2 = list[0..(i+1)]
list = list - list2
count = 0
while count <= len+1
...
you are trying to split the array in two. You get list2 which is the first half of the array and then try and get the second half by subtracting list2 from list.
The problem with using subtract here is that if you have duplicates it will remove them and make your lists too short.
In the example [3790,1,780,55,23,50,1111,60,50] you should have a 50 in the first array and a 50 in the second half.
But using subtract removes one of those 50.
When you add the two temporary lists back together you are now one element short (the missing 50) and you get an out of bounds error when you get to the end of the array and try and access this 9th element which no longer exists.
Instead of using subtract here simply use the same method you used to make list2.
list2 = list[0..(i+1)] # All elements in list from position 0 to i+1
list = list[(i+2)..-1] # All elements in list from position i+2 to end of list
Now list and list2 are just the original list split, and when you add them back together are the end they should be the same length
def insertion_sort(list)
num = list.length
for i in (0..(num-2))
if list[i] > list[i+1] && i == 0
list[i], list[i+1] = list[i+1], list[i]
i+=1
elsif list[i] == list[i+1]
i+=1
elsif list[i] > list[i+1] && i > 0
len = (list[0..(i+1)].length)
list2 = list[0..(i+1)]
list = list[(i+2)..-1]
count = 0
while count <= len+1
if list2[len-1] < list2[len-2]
list2[len-2],list2[len-1]= list2[len-1],list2[len-2]
elsif list2[len-1] == list2[len-2]
count+=1
len-=len
else
count+=1
len-=1
end
end
list = list2 + list
end
end
list
end
p insertion_sort([2,1,4,8,7,3,100,99,8])
p insertion_sort([2,1,4,8,8,7,3,100,99])
p insertion_sort([3790,780,780,1,55])

Ruby FizzBuzz using arrays, my logic seems right but it is getting an error

FizzBuzz, a classic problem, returns all the numbers up to N with a slight twist. If a number is divisible by 3, it is replaced with "fizz". If it's divisible by 5, it's replaced with "buzz". If it's divisible by both, it's replaced with "fizzbuzz"
I keep getting this Error message:
comparison of Fixnum with nil failed
Can someone explain this error message to me please? Also why is the code not working?
def fizz_buzz(n)
arr = (1..n).to_a
i = 0
while arr[i] < arr[n]
if i % 3 == 0 && i % 5 == 0
arr[i] = 'fizzbuzz'
elsif i % 3 == 0
arr[i] = 'fizz'
elsif i % 5 == 0
arr[i] = 'buzz'
else
arr[i] = i
i += 1
end
end
return arr
end
fizz_buzz(12)
Your conditions are just a bit off, give this a try:
def fizz_buzz(n)
arr = (1..n).to_a
i = 0
while i < n
if arr[i] % 3 == 0 && arr[i] % 5 == 0
arr[i] = 'fizzbuzz'
elsif arr[i] % 3 == 0
arr[i] = 'fizz'
elsif arr[i] % 5 == 0
arr[i] = 'buzz'
end
i+=1
end
return arr
end
Trying to access arr[n] puts you outside the bounds of the array which returns nil in Ruby.
You can update the code the ruby way, by using blocks and guards, I don't remember last time I used a while loop in ruby :)
Also, Array.new accepts a block as an argument which you can exploit to build your Array in a single step:
def fizz_buzz(n)
Array.new(n) do |index|
x = index + 1
case
when x % 3 == 0 && x % 5 == 0 then "fizzbuzz"
when x % 3 == 0 then "fizz"
when x % 5 == 0 then "buzz"
else x
end
end
end
Notice I used 1 as a base index and not 0, you can just remove x = index + 1 and replace x with index to have it working in a zero index base
A solution with a block instead of the while loop, and guards
def fizz_buzz(n)
arr = (1..n).to_a
0.upto(n - 1) do |i|
arr[i] = "fizzbuzz" and next if i % 3 == 0 && i % 5 == 0
arr[i] = "fizz" and next if i % 3 == 0
arr[i] = "buzz" if i % 5 == 0
end
arr
end
#brad-melanson beat me to the straight-forward answer to your question, so I'll share an answer which uses some common Ruby idioms (passing a range to the Array constructor and map), which simplify things, prevent you from having to do any iteration bookkeeping and prevent the possibility of off-by-one errors, out-of-bounds errors, etc.
def fizz_buzz(n)
Array(1..12).map do |n|
if n % 3 == 0 && n % 5 == 0
'fizzbuzz'
elsif n % 3 == 0
'fizz'
elsif n % 5 == 0
'buzz'
else
n
end
end
end
result = fizz_buzz 12
# result => [1, 2, "fizz", 4, "buzz", "fizz", 7, 8, "fizz", "buzz", 11, "fizz"]

Project Euler #6 in Ruby (What's the difference?)

I solved #6 for Project Euler using two different methods, but the second one just happened to be coincidental. I don't really understand why I don't have to return the square of new_sum like I did for my first method. Does anyone know what's the major difference between the two?
def square_difference(num)
new_sum = 0
sum = 0
while num >= 1
sum += num**2 && new_sum += num
num -= 1
end
return new_sum**2 - sum
end
AND
def square_difference(num)
new_sum = 0
sum = 0
while num >= 1
new_sum += num && sum += num**2
num -= 1
end
return new_sum - sum
end
The precedence of && is higher than that of +=. So these expressions:
sum += num**2 && new_sum += num
new_sum += num && sum += num**2
don't work as you expected. The first one just happen to provide the seemingly "correct" result.
Divide them into separate lines and you'll see the difference. Or, at least use and instead of &&. and has a lower precedence than that of +=.
Both formulas have the same subtle bug. I stepped through it a couple of times to understand what was going on.
From the second one:
[30] pry(main)> square_difference(4)
new_sum: 16, sum: 16, num: 3
new_sum: 41, sum: 25, num: 2
new_sum: 70, sum: 29, num: 1
new_sum: 100, sum: 30, num: 0
=> 70
We can see that new_sum does not seem to be behaving as intended.
What is actually happening is that new_sum += num && sum += num**2 is being evaluated to new_sum += (num && sum += num **2), which in turn evaluates to new_sum += (sum += num **2)
This is a result of the && operator, which has higher precedence (as Yu Hao pointed out) and returns the first value which determines whether the AND condition is satisfied.
[31] pry(main)> 2 && 2
=> 2
[32] pry(main)> 2 && 4
=> 4
[33] pry(main)> 4 && 2
=> 2
[34] pry(main)> nil && 2
=> nil
[35] pry(main)> 2 && nil
=> nil

ruby inject with conditional in block?

doing the first Project Euler question: summing the multiples of 3 and 5 between 1 and 1000, I came up with this (pretty simple)
sum = 0
1.upto(999) { |i| sum += i if 0 == i%3 || 0 == i%5 }
sum
but I thought this would work but it doesn't, can someone show me what I'm doing wrong, or why it doesn't work?
1.upto(999).inject(0) { |sum, i| sum + i if 0 == i%3 || 0 == i%5 }
thanks!
inject passes the result of the block through to the next iteration as the first argument. Your block will return nil when your if statement is false, which then gets passed back in as sum.
To get the correct answer, the block should return the current sum when it's false:
1.upto(999).inject(0) { |sum, i| (0 == i%3 || 0 == i%5) ? sum + i : sum }
Complementary answer: if you're about to tackle Euler problems you should start to build your own extensions of reusable code. In this case, the first extension would be Enumerable#sum:
module Enumerable
def sum
inject(0, :+)
end
end
And now you can write a solution that separates the condition of the summatory (you can read it out loud and it makes sense, that's typical of functional/declarative style):
1.upto(999).select { |x| x % 3 == 0 || x % 5 == 0 }.sum
You could even push it one step further and create Fixnum#divisible_by? so you can write:
1.upto(999).select { |x| x.divisible_by?(3) || x.divisible_by?(5) }.sum
More: here it's not a problem, but later on strict implementations (those using arrays) will require too much memory. Try then with laziness:
require 'lazy'
1.upto(999).lazy.select { |x| x % 3 == 0 || x % 5 == 0 }.sum
1.upto(999).inject(0) { |sum, i| sum += i if 0 == i%3 || 0 == i%5; sum }
Would also work (note the +=).
Or, use & proc which addresses self.
(1..999).select{|x| x%3==0||x%5==0}.inject &:+
(1..999).to_a.keep_if{|d| d%3 == 0 || d%5 == 0}.reduce(:+) for completeness.

check whether any number in one array is less than some number in the other array

This seems like a pretty common question. Sadly I could not find it on SO. If this is a duplicate question; I apologize for that.
Say I have two integer arrays A and B:
A = [17, 3, 9, 11, 11, 15, 2]
B = [1, 13]
I need to return a true or a false if any element of array A is less than any element of array B.
The trivial way to do this was use 2 each loops (O(n^2) complexity)
def is_greater?(a,b)
retVal = false
b.each { |element|
a.each { |value|
if (value < element)
retVal = true
break
end
}
}
return retVal
end
is_greater?(A,B) => true
I also sorted out the elements in both the arrays and then used a single while loop to determine whether the element in A is less than that in B.
A.sort!
B.sort!
def is_greater?(a,b)
retVal = false
i = 0
j = 0
while (i < a.length && j < b.length)
if (a[i] < b[j])
retVal = true
break
elsif (a[i] == b[j])
i = i + 1
j = j + 1
else
j = j + 1
end
end
return retVal
end
is_greater?(A,B) => true
I was wondering whether there is an efficient, precise way to do it in terms of lines of code. I was trying to figure out how to use the any? block, but it did not make any sense to me.
Yes, you can use Enumerable methods #any? and #min
For each item in a, return true if it is less than max:
max = b.max
a.any?{|x| x < max}
It should be enough to just check the minimum of the first array against the maximum of the second.
a.min < b.max
The only way this conditional returns false is if every element is b is less than every element in a.
The complexity is O(m+n) which is the single iteration through both a and b.

Resources