The brief
A small logistics team sends a daily file to your program. The file has three parts: how many readings were taken, the readings themselves, and a word that identifies the shipment. Each day the team needs a short report with the total, the average, the smallest and largest reading, how many readings are even, whether the shipment word is a palindrome, and which letter appears most often in the word.
Your job is to write the program that produces that report. It must read the input from the standard input, which is the input box in this course or a file redirected into the program. It must print the report in the exact format given below, because the team's script parses it line by line. The program is judged by running it on several inputs, some of them large, and comparing the output with the expected text.
This assignment uses every idea from the module. You will need variables and the basic kinds of values for the readings and the totals, sys.stdin for the input, string methods and the two-pointers pattern for the palindrome, a list of 26 counters for the letters, and a careful rounding rule for the average. A solution that handles all of this correctly is a complete small program, which is what an interviewer means by an implementation question.
The input format
The input has exactly three lines.
- A line with one integer
n, wherenis at least 1 and at most 100000. - A line with
nintegers separated by single spaces. Each integer is between-1000000000and1000000000, inclusive. - A line with one word of lowercase letters
atoz. The word has between 1 and 100000 letters, and it contains no spaces.
You may assume the input follows this format exactly. Your program does not need to check for bad input. It does need to handle every valid input, including the smallest and largest ones.
The output format
The program prints exactly six lines, in this order, with these labels and this spacing.
Sum:followed by the sum of all the readings, as an integer with no decimal point.Average:followed by the average of the readings, with exactly two digits after the decimal point. Use the normal rounding rule, where an exact half rounds away from zero, and print a leading minus sign for negative averages.Min:followed by the smallest reading, then a space, thenMax:and the largest reading.Evens:followed by how many readings are even. Zero counts as even, and so do negative even numbers such as-4.Palindrome: yesif the word reads the same backwards, orPalindrome: noif it does not.Most common letter:followed by one letter, then(countfollowed by its count and a closing bracket. If two or more letters tie for the highest count, print the one that comes first in the alphabet.
Worked examples
Here is the first example, with the input shown in the input box and the output that must appear under it.
5
3 9 2 9 7
levelSum: 30
Average: 6.00
Min: 2 Max: 9
Evens: 1
Palindrome: yes
Most common letter: e (count 2)Check the output by hand before you run anything. The sum is 3 + 9 + 2 + 9 + 7, which is 30. The average is 30 divided by 5, which is 6, printed with two decimals as 6.00. The smallest reading is 2 and the largest is 9. Only the 2 is even. The word level is a palindrome. Its letters are l twice, e twice and v once, so l and e tie for the highest count, and e comes first in the alphabet.
Now the second example. Its numbers include negatives, and its average has a repeating decimal.
3
-4 -10 7
abcSum: -7
Average: -2.33
Min: -10 Max: 7
Evens: 2
Palindrome: no
Most common letter: a (count 1)The average is -7 divided by 3, which is -2.3333..., and it is printed as -2.33. The two negative even numbers are -4 and -10. The word abc has three letters with count 1, so the tie goes to a.
A third example checks the smallest case and a large negative value. Its only reading is -2000000000. Python int does not overflow, so the sum is exact without any special type. In a language with a 32-bit int, this sum would need a 64-bit type.
1
-2000000000
xSum: -2000000000
Average: -2000000000.00
Min: -2000000000 Max: -2000000000
Evens: 1
Palindrome: yes
Most common letter: x (count 1)A single letter is a palindrome, because the two pointers start on the same index and the loop never runs.
Requirements checklist
Copy this list into your notes and tick each line when you have tested it.
- The program reads
nand then exactlynreadings, in order, from the standard input. - The sum is correct for a test with 100000 readings near one billion.
- The minimum and maximum come from the readings themselves, not from a value such as 0.
- The average divides by
nwith/, so the fraction is kept. The output uses two decimal places. - The average is rounded with
DecimalandROUND_HALF_UP, so an exact half such as 0.625 prints as0.63. - Even readings are counted with
value % 2 == 0, and negative values are handled. - The palindrome check uses two pointers and stops at the first mismatch.
- The letter counts use a list of 26 counters indexed by
ord(ch) - ord("a"). - The most common letter is chosen with a strict
>in an alphabetical scan, so ties go to the earlier letter. - The output has exactly six lines with the labels and spacing given in the format section.
- The program was tested with the three examples above, with n equal to 1, and with a word of one repeated letter.
The grading rubric
The rubric describes three levels. Your score is the level your program reaches on the hidden test inputs, not the level you believe you reached. Read each level carefully, because the difference is in the details.
60 percent: the program runs and prints the right shape. The program reads the input and prints six lines with the right labels. The sum, minimum and maximum are correct on the small examples. Some lines may be wrong on larger inputs, or the palindrome or the letter count may be missing. A solution at this level often divides with // for the average, so the average is a whole number, or it prints the average without two decimal places.
80 percent: every line is correct on ordinary inputs. All six lines are right on the three examples and on random inputs of moderate size. The average has the decimal part and two digits after the point. The palindrome check handles odd and even lengths. The tie rule for letters is correct. A solution at this level may still break on the edge cases: a single reading, a word of one letter, or an average that is an exact half.
100 percent: every line is correct on every valid input, and the code is clean. The program passes the edge cases above and also the large tests, which have up to 100000 readings and words. The code uses names that say what they hold, and it avoids repeating the same loop without a reason. The solution runs in time proportional to n plus the length of the word, and it uses a fixed amount of memory for the counts. Within the code, a short comment states what each section computes, so a reviewer can follow it without running it.
A useful test is to ask: if I change the constraint on n from 100000 to 10 million, which line of my code breaks first? A 100 percent solution has no line that breaks because of a plausible larger input.
Hints, one step at a time
Try the assignment with no hints first. If you get stuck, read one hint at a time. Each hint is a small step, not the whole answer.
Hint 1: the reading order. Read all the input with sys.stdin.read().split(). The first token is n. The next n tokens are the readings, and the token after them is the word. This order works whether the readings are on one line or several.
Hint 2: the running values. You need the sum, the smallest, the largest and the count of even readings. The built-in functions sum, min and max give three of them in one call each. The count of evens can be written as sum(1 for value in readings if value % 2 == 0), which adds 1 for each even reading.
Hint 3: the average. The plain form total / n gives a float, and the format f"{average:.2f}" rounds it. That rounding rule rounds exact halves to the even digit, so 5 / 8 prints as 0.62. The brief asks for the normal rule, so compute the average with Decimal, quantize it to two places with ROUND_HALF_UP, and print the result. Import Decimal and ROUND_HALF_UP from the decimal module.
Hint 4: the palindrome. Copy the two-pointers loop from the strings lesson. Start left at 0 and right at len(word) - 1. Keep a boolean is_palindrome, set it to False on the first mismatch, and use break to leave the loop. Then print yes or no with a conditional expression.
Hint 5: the most common letter. Create counts = [0] * 26. Loop over the word and add one to counts[ord(ch) - ord("a")]. Then find the best index with a loop from 0 to 25. Keep a variable best that starts at 0. For each k, replace best with k only when counts[k] > counts[best]. The strict > is what gives the earlier letter the win on a tie. Print the letter with chr(ord("a") + best).
Hint 6: the output. Print the six lines with print and f-strings. Make sure the labels match the format exactly, including the space after each colon and the space before Max:.
A complete reference solution
Try your own version first. When you compare, check the output on the three examples before you read the code closely. The code is a complete program, and you can run it by typing the examples into the input box or by redirecting a file.
Show the answer
import sys
from decimal import Decimal, ROUND_HALF_UP
def main():
data = sys.stdin.read().split()
n = int(data[0])
readings = list(map(int, data[1:1 + n]))
word = data[1 + n]
# Summary numbers for the readings.
total = sum(readings)
average = (Decimal(total) / Decimal(n)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
smallest = min(readings)
largest = max(readings)
evens = sum(1 for value in readings if value % 2 == 0)
# The palindrome check: compare from both ends.
left = 0
right = len(word) - 1
is_palindrome = True
while left < right:
if word[left] != word[right]:
is_palindrome = False
break
left += 1
right -= 1
# The letter counts, then the first letter with the highest count.
counts = [0] * 26
for ch in word:
counts[ord(ch) - ord("a")] += 1
best = 0
for k in range(26):
if counts[k] > counts[best]:
best = k
print(f"Sum: {total}")
print(f"Average: {average}")
print(f"Min: {smallest} Max: {largest}")
print(f"Evens: {evens}")
print("Palindrome: yes" if is_palindrome else "Palindrome: no")
print(f"Most common letter: {chr(ord('a') + best)} (count {counts[best]})")
main()The solution reads the input in one pass over the tokens, and it keeps only the readings and 26 counters. The time is proportional to n plus the length of the word. Python int holds the largest total the brief allows, which is 100000 times one billion, or 10 to the power 14, so the sum needs no special type. The Decimal average avoids binary rounding surprises. The main function only groups the steps, and functions are covered in a later module, so you can also write the same lines at the top level.
Testing your program
Test in this order, and do not move on until each step passes.
First, run the three examples in the brief and compare every line with the expected text. A single extra space is a failure in the team's script, so compare carefully.
Second, test the edge cases. Use n equal to 1 with a positive reading, a word of one letter, a word of two equal letters, and a word of two different letters. Check the palindrome answer and the tie rule each time.
Third, test a large sum. Generate 100000 readings of one billion each and check that the sum is 100000000000000, which is 10 to the power 14. Then check the average, which must print as 1000000000.00. Generating the input with a short script, and redirecting it into the program, is the easiest way to do this.
Fourth, test the negative side. Use readings that are all negative, and check that the minimum and maximum are the right way round. A solution that starts max at 0 fails this test, and that failure is the reason the brief asks you to take the extremes from the readings themselves.
Fifth, test the layout. Put all the readings on one line, then on several lines, and check that the answer does not change. Your reads should use tokens, so the layout must not matter.
Explaining your solution
An interviewer would ask you to explain the solution in a few minutes. Practise these three points out loud.
Start with the complexity: "The program reads n readings and scans the word a constant number of times, so the time is O(n) plus the length of the word, and the extra memory is O(1), because the 26 counters do not grow with the input." Then state the numeric decisions: "The sum is exact because Python integers do not overflow. The average uses Decimal with half-up rounding, because the brief asks for the normal rule, and Python's default formatting rounds exact halves to the even digit." Finally, name the two patterns: "The palindrome uses two pointers from both ends, and the most common letter uses a counter list indexed by the letter."
If you can say those three things in under two minutes, and then run the program on the examples while the interviewer watches, you have shown the full skill this module teaches.
What this module covered
- Python scripts, the interpreter, and how to read the messages Python prints for syntax errors and runtime errors.
- Names and values, the basic kinds
int,float,str,boolandNone, and integer division with/and//. - Strings: indexes, slices, methods, immutability,
==, joining in a list, palindromes, anagrams and letter counts. - Conversions with
int(),float()andstr(), rounding rules,ordandchr, and parsing text into numbers. - Reading input with
input()andsys.stdin, reading tokens across lines, reading until the end of input, and fast reads for large inputs.