Practice problem
Strictly Increasing Check
MediumSolve in Python · graded against 2 sample tests and a hidden test set in your browser · Published
The Bug Report
The program reads several sequences of integers, one per line, and prints yes or no for each: yes
when the sequence is strictly increasing, meaning every value is greater than the one before it, and no
otherwise. It runs, it prints one answer per sequence, and the answers are a mixture of right and wrong.
Input that shows the problem
3
1 2 3
1 5 3
4 4What the program prints
yes
yes
noWhat it should print
yes
no
noThe middle sequence, 1 5 3, is reported as increasing even though it drops from 5 to 3. The first and
third answers are right. Sequences that go wrong at their first pair, like 4 4, are always caught; the
ones that go wrong later are the ones being let through.
Input Format
The input has t + 1 lines:
- Line 1: a single integer t, the number of sequences.
- The next t lines: one sequence each, as integers separated by single spaces. A sequence may hold a single value.
Output Format
Print t lines, one per sequence in the order they were given. Each line is the lowercase word yes if that
sequence is strictly increasing, or no if it is not.
How to Debug It
The report contains a distinction worth taking seriously: failures at the first pair are caught, failures
later are not. Before touching the code, test whether that is really the rule by walking a fault along the
sequence. Run four one-sequence inputs — a count line of 1, then the sequence — using 2 1, 1 2 1, 1 2 3 1
and 1 2 3 4 1. All four should print no.
If only the first does, you have established something precise — the function stops paying attention after
the first pair — and you have done it without reading a line of the loop.
Now confirm it directly instead of inferring it. Make i visible: put a print of i as the first
statement in the loop body and run 1 2 3 4 4, a sequence with four pairs that fails only at the last
one. Count the lines of trace. Four pairs should produce four lines; if you get one, the loop is not
being cut short by the data, it is being cut short by control flow. Only two statements in that loop can
end the function early, so look at what each of them does and when.
The hypothesis to state is about which of those two exits fires, and on what kind of input it fires wrongly. It helps to reason about what each answer means: "this sequence is not increasing" is something a single bad pair proves on its own, while "this sequence is increasing" is a claim about every pair at once and cannot be settled by looking at one of them. Change one thing in light of that, re-run all four of the moving-fault inputs, and then re-run the second sample — a single value, and a first-pair failure — both of which were already correct and must remain so.
What Was Wrong
Both return statements were inside the loop:
for i in range(len(values) - 1):
if values[i] >= values[i + 1]:
return False
return TrueThe return False is right where it belongs. One out-of-order pair is enough to settle the question, so
returning immediately is both correct and efficient.
The return True is not. Sitting at the end of the loop body, it runs on the first pass — as soon as
one pair turns out to be in order — and returns from the whole function before the loop can reach pair
number two. So the function never examines more than a single pair: if the first pair is out of order it
answers no, and otherwise it answers yes regardless of what the rest of the sequence does. That is
exactly the behaviour in the report. 1 5 3 passes because 1 < 5, and the 5 3 pair is never looked at.
The fix is to move that return True out of the loop, where the duplicate already sits, leaving the loop
with a single exit:
for i in range(len(values) - 1):
if values[i] >= values[i + 1]:
return False
return TrueThe general shape is worth remembering, because this pattern comes up whenever code answers "do all of
these satisfy something?". A counterexample can end the search the moment it is found, so the negative
answer belongs inside the loop. The positive answer is a statement about everything at once, so it can
only be given after the loop has run out of things to check. Reaching the end of the loop is the proof; the
return True is what that proof concludes. (This also explains why a one-value sequence answers yes for
free — there is no pair to check, the loop body never runs, and the claim holds trivially.)
Common Mistakes
- Moving the
return Falseout instead, and keeping a flag. A booleanokvariable set toFalseon a bad pair, returned after the loop, is correct — but it keeps scanning a sequence whose answer is already settled. If you use a flag,breakout when it flips, and be aware you have added a variable whose value has to be right in two places instead of one. - Using
>instead of>=in the comparison. That accepts equal neighbours, so4 4and1 2 2 3come back asyes. Strictly increasing rules out equal values, and the word "strictly" in the statement is what tells you which of the two comparisons to write. - Forgetting the single-value sequence when restructuring. A rewrite that starts by comparing
values[0]andvalues[1]reaches past the end of a one-value list and crashes. The loop boundlen(values) - 1already handles it by running zero times, which is one reason to fix the control flow rather than rewrite the loop.
Sample tests
Sample 1
Input
3 1 2 3 1 5 3 4 4
Expected output
yes no no
The first sequence rises all the way. The second rises then falls, so it fails at its second pair. The third repeats a value, and strictly increasing does not allow equal neighbours.
Sample 2
Input
2 7 3 1
Expected output
yes no
A single value has no pair to break the rule. The second sequence falls at its very first pair — which, as the bug report explains, is the one kind of failure the broken program does catch.
Your solution
Run tries the first sample. Submit grades against every sample and the hidden tests. Your code is saved in this browser as you go.
Press Esc then Tab to move keyboard focus out of the code editor.
Output will appear here after you run your code.