The Tail Trimmer

An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
easy
Seniority
L3

Problem

What does a request log lst, held in arrival order, look like once the entry k positions back from the newest end is dropped? Return it as a new list without touching lst, and when k reaches past the oldest entry, return the log unchanged.

Remove the k-th item from the back without counting forward first.

Example 1

Input:

lst = [1,2,3,4,5], k = 2

Output:

[1,2,3,5]

Example 2

Input:

lst = [1,2,3], k = 1

Output:

[1,2]

Worked solution and explanation

This is an index-translation problem dressed up as log housekeeping. Anyone can say 'the k-th from the end'. The skill is turning that into a forward position, len(lst) - k, and checking k against the length before you touch anything. The trap is Python's negative indexing: it looks made for this, and it is wrong at both edges. lst[:-k] + lst[-k+1:] falls apart at k = 1, because -k+1 is 0 and lst[0:] is the whole log, so nothing gets removed and a full copy is glued back on. lst.pop(-k) raises IndexError once k reaches past the oldest entry, where the contract says to hand the log back unchanged.

Reasoning it out

Step 1: Guard before you compute

Check k > len(lst) first. That one comparison covers both an oversized k and the empty log, and it is the only way k can go wrong, so the rest of the function never sees a bad position. The k <= 0 half is defensive: the contract promises a positive k.

Step 2: Flip the position to count from the front

The newest entry sits at len(lst) - 1 and is k = 1, so the k-th from the end sits at len(lst) - k. Check it at both boundaries: k = 1 gives the last index, and k = len(lst) gives 0, the oldest entry.

Step 3: Slice around the gap

lst[:idx] + lst[idx + 1:] is everything before the entry plus everything after it. Both bounds are non-negative and in range, so there is no sign flip to reason about, and the caller's list is only read.

Forward index after a bounds guard
def remove_kth_from_end(lst: list, k: int) -> list:
    if k <= 0 or k > len(lst):
        return lst
    idx = len(lst) - k
    result = lst[:idx] + lst[idx + 1:]
    return result
Negative-index shortcut
lst[:-k] + lst[-k+1:] at k = 1: the second slice is lst[0:], the full log, so nothing is dropped. lst.pop(-k) with k = 9 on three entries raises IndexError, and when it does work it mutates the caller's list.
Forward index after a guard
idx = len(lst) - k runs only after k > len(lst) has returned early. Every slice bound lies between 0 and len(lst), the same line handles k = 1 and k = len(lst), and the input is never modified.

Common follow-up questions