Schedule > More Programming Practice in Python

Here are some practice problems for the midterm exam. You are also welcome to solve these problems in Java if Java is more comfortable to you. That said, our software engineering projects will be mostly utilizing Python and JavaScript, so it’s good practice to work with both languages.

If your solution uses nested loops, there is probably a better way — often a set or dictionary. Prefer the clearer, more efficient approach when you can.

Copy a stub into a file (or a notebook cell), fill in the body, and run the two asserts.

1. Word frequency

Count how often each word appears. Ignore capitalization; treat punctuation as part of the word for now (split on spaces only).

def word_frequency(text: str) -> dict[str, int]:
    """Return a map from lowercase word -> count."""
    pass


assert word_frequency("to be or not to be") == {"to": 2, "be": 2, "or": 1, "not": 1}
assert word_frequency("Hi hi HI") == {"hi": 3}

2. First duplicate

Return the first value that appears a second time. If none, return None.

def first_duplicate(nums: list[int]) -> int | None:
    pass


assert first_duplicate([2, 5, 1, 2, 3, 5]) == 2
assert first_duplicate([1, 2, 3, 4]) is None

3. Anagrams

Return True if a and b use the same letters with the same counts (ignore spaces and capitalization).

def are_anagrams(a: str, b: str) -> bool:
    pass


assert are_anagrams("listen", "silent") is True
assert are_anagrams("hello", "world") is False

Walkthrough: NeetCode – Valid Anagram

4. Student averages

Given (student, grade) pairs, return each student’s average grade.

def student_averages(pairs: list[tuple[str, float]]) -> dict[str, float]:
    pass


assert student_averages([("Ada", 90), ("Ada", 100), ("Bob", 80)]) == {"Ada": 95.0, "Bob": 80.0}
assert student_averages([("Kai", 70), ("Kai", 80), ("Kai", 90)]) == {"Kai": 80.0}

5. Two-sum

Return any two indices whose values add to target. Assume exactly one solution exists.

def two_sum(nums: list[int], target: int) -> tuple[int, int]:
    pass


assert sorted(two_sum([2, 7, 11, 15], 9)) == [0, 1]
assert sorted(two_sum([3, 2, 4], 6)) == [1, 2]

Walkthrough: NeetCode – Two Sum

6. Shopping total

def shopping_total(items: list[str], prices: dict[str, int]) -> int:
    """Sum price[item] for each item in items."""
    pass


assert shopping_total(
    ["apple", "banana", "apple", "orange", "banana", "apple"],
    {"apple": 2, "banana": 1, "orange": 3},
) == 11
assert shopping_total(["orange"], {"apple": 2, "banana": 1, "orange": 3}) == 3

7. Character histogram

Count every character, including spaces.

def char_histogram(s: str) -> dict[str, int]:
    pass


assert char_histogram("aab") == {"a": 2, "b": 1}
assert char_histogram("hi hi") == {"h": 2, "i": 2, " ": 1}

8. Course enrollment

Map each course to the list of students enrolled (preserve encounter order; allow duplicates if a student appears twice).

def course_enrollment(pairs: list[tuple[str, str]]) -> dict[str, list[str]]:
    """pairs are (student, course)."""
    pass


assert course_enrollment([("Ada", "338"), ("Bob", "202"), ("Ada", "202")]) == {
    "338": ["Ada"],
    "202": ["Bob", "Ada"],
}
assert course_enrollment([("Kai", "101"), ("Kai", "101")]) == {"101": ["Kai", "Kai"]}

9. Common elements

Return values that appear in both lists (any order is fine; no duplicates in the result).

def common_elements(a: list[int], b: list[int]) -> list[int]:
    pass


assert sorted(common_elements([1, 2, 2, 3], [2, 3, 4])) == [2, 3]
assert sorted(common_elements([1, 2], [3, 4])) == []

10. Most frequent

Return the integer that occurs most often. If there is a tie, return any of the tied values.

def most_frequent(nums: list[int]) -> int:
    pass


assert most_frequent([1, 3, 2, 3, 1, 3]) == 3
assert most_frequent([7, 7, 1, 1, 7]) == 7

Harder

11. Group anagrams

Group words that are anagrams of each other. Order of groups and words within a group does not matter.

def group_anagrams(words: list[str]) -> list[list[str]]:
    pass


def _normalize(groups: list[list[str]]) -> list[tuple[str, ...]]:
    return sorted(tuple(sorted(g)) for g in groups)


assert _normalize(group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"])) == _normalize(
    [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]]
)
assert _normalize(group_anagrams(["a"])) == _normalize([["a"]])

Walkthrough: NeetCode – Group Anagrams

12. First unique character

Return the first character that appears exactly once. If none, return None.

def first_unique_char(s: str) -> str | None:
    pass


assert first_unique_char("leetcode") == "l"
assert first_unique_char("aabb") is None

Walkthrough: NeetCode – First Unique Character

13. Top-k frequent

Return the k most frequent numbers (any order is fine among ties).

def top_k_frequent(nums: list[int], k: int) -> list[int]:
    pass


assert sorted(top_k_frequent([1, 1, 1, 2, 2, 3], 2)) == [1, 2]
assert sorted(top_k_frequent([4, 4, 4, 5], 1)) == [4]

Walkthrough: NeetCode – Top K Frequent Elements

14. Subarray sum equals k

Return how many contiguous subarrays sum to k.

def subarray_sum(nums: list[int], k: int) -> int:
    pass


assert subarray_sum([1, 1, 1], 2) == 2  # because [1,1] at indices 0–1 and [1,1] at indices 1–2
assert subarray_sum([1, 2, 3], 3) == 2  # because [1, 2] and [3]

Walkthrough: NeetCode – Subarray Sum Equals K

15. Longest consecutive sequence

Return the length of the longest run of consecutive integers (order in the list does not matter). Aim for better than sorting if you can.

def longest_consecutive(nums: list[int]) -> int:
    pass


assert longest_consecutive([100, 4, 200, 1, 3, 2]) == 4  # 1,2,3,4
assert longest_consecutive([0, 3, 7, 2, 5, 8, 4, 6, 0, 1]) == 9

Walkthrough: NeetCode – Longest Consecutive Sequence

UNC Asheville Department of Computer Science