HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

"Can a given array be made strictly increasing by removing one number?"

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cannumbermadestrictlyremovingarrayoneincreasinggiven

Problem

The premise of the problem is that given an array of numbers, can you remove only one to make it a strictly increasing sequence?

  • [1, 1, 1, 2, 3] would be false because if you remove one of the 1s the array would still start off non-increasing because of the other two remaining 1s before it increased.



  • [1, 2, 3, 4, 99, 5, 10] would be true because you can remove the 99 and the remaining array [1, 2, 3, 4, 5, 10] would be strictly increasing.



  • [1, 88, 2, 3, 4, 99, 5, 6] would be false because removing any number would still leave an array that would not strictly increase.



For [1, 1] it would return true because even though removing one of the 1s would only leave one 1 which by definition can't increase sequentially because it is only one thing, I did not write the problem and this is the response they wanted.

and so on....

My questions

I've clearly made this code too complex, but it does work. Below my code is the tests that I used to check it with the expected returns commented out next to each.

How can I refactor this code to simplify it? Is there a way to do this without using chunk_while?

```
def almost_increasing_sequence(sequence)
array_of_arrays = sequence.chunk_while {|i, j| i 2
puts false
else
if (array_of_arrays[0].last array_of_arrays[1].first) == 1
if (array_of_arrays[0][-2] array_of_arrays[1][0]) == -1
puts true
elsif (array_of_arrays[0].last array_of_arrays[1][1]) == -1
puts true
elsif (array_of_arrays[0][-2]) == nil
puts true
else
puts false
end
else
puts true
end
end
end

almost_increasing_sequence([1, 2, 3, 4, 99, 5, 6]) #true
almost_increasing_sequence([1, 3, 2]) #true
almost_increasing_sequence([10, 1, 2, 3, 4, 5]) #true
almost_increasing_sequence([0, -2, 5, 6]) #true
almost_increasing_sequence([1, 2, 3, 4, 3, 6]) #true
almost_increasing_sequence([1, 1]) #true
almost_increasing_sequence([100, 200, 300, 400, 99, 50

Solution

I'm not completely sure I've interpreted the requirements correctly, but I think this should do it:

def almost_increasing_array?(array, tolerance)
  unmatched = 0
  array[1..-1].each_with_index do |item, index|
    unmatched += 1 if array[index] >= item
    return false if unmatched > tolerance
  end
  true
end


The tolerance is extra but it basically says this:

  • Ignore the first item in the array



  • For the rest, compare them to the previous item



  • If the previous item was more than this, increment 'unmatched' count.



  • If more than the tolerance didn't increase, false. It's not 'almost increasing'



It looks like it works for all cases.

almost_increasing_array?([1, 3, 5], 1) # true
almost_increasing_array?([5, 4, 3, 2, 1], 1) # false
almost_increasing_array?([1, 2, 5, 4], 1) # true (only one decrease)
almost_increasing_array?([1, 7, 5, 4], 1) # false (two decreases)
almost_increasing_array?([1, 7, 5, 4], 2) # true (two decreases, but we said that's okay)


You could easily simplify by removing the tolerance argument (hard coding 1).

def almost_increasing_array?(array)
  unmatched = 0
  array[1..-1].each_with_index do |item, index|
    unmatched += 1 if array[index] >= item
    return false if unmatched > 1
  end
  true
end


Weaknesses:

  • This includes an array which is fully increasing, too.



  • This will fail as soon as an issue is found, but it may run slowly on huge arrays where there's a decrease right at the end.



Strengths:

  • It's pretty simple to understand.



  • This doesn't even have to be an array, it'll work for an instance of any Ennumerable class. Such as ActiveRecord::Relation, or Hash.

Code Snippets

def almost_increasing_array?(array, tolerance)
  unmatched = 0
  array[1..-1].each_with_index do |item, index|
    unmatched += 1 if array[index] >= item
    return false if unmatched > tolerance
  end
  true
end
almost_increasing_array?([1, 3, 5], 1) # true
almost_increasing_array?([5, 4, 3, 2, 1], 1) # false
almost_increasing_array?([1, 2, 5, 4], 1) # true (only one decrease)
almost_increasing_array?([1, 7, 5, 4], 1) # false (two decreases)
almost_increasing_array?([1, 7, 5, 4], 2) # true (two decreases, but we said that's okay)
def almost_increasing_array?(array)
  unmatched = 0
  array[1..-1].each_with_index do |item, index|
    unmatched += 1 if array[index] >= item
    return false if unmatched > 1
  end
  true
end

Context

StackExchange Code Review Q#158658, answer score: 2

Revisions (0)

No revisions yet.