cswork / libraryOpen practice workspace

Coding questions

Check if a numeric string is divisible by 8

Determine whether a very large non-negative integer given as a decimal string is divisible by 8 without converting the whole string to an integer. The key insight is that only the last three digits matter (since 1000 is a multiple of 8), giving an O(1) check; a streaming modular-remainder approach is the O(n) alternative.

Question

You are given a very large non-negative integer represented as a decimal string s (it may be too large to fit in standard 64-bit integer types).

Write a function that returns True if the number represented by s is divisible by 8, otherwise return False.

Constraints / Requirements

  • Do not convert the entire string to an integer type (e.g., no int(s)).
  • 1 <= len(s) <= 10^6.
  • s consists only of digits '0'–'9'.
  • Leading zeros may exist (e.g., "00016").

Examples

  • s = "16" → True
  • s = "123" → False
  • s = "1000" → True

Numeric String Divisible by 8

Return whether a very large non-negative decimal string is divisible by 8 without converting the whole string.

Hints

  1. A decimal integer is divisible by 8 iff its last three digits are divisible by 8.

Solution

Because 1000 is a multiple of 8, only the last three digits of the number affect divisibility by 8. The clean O(1) approach is to parse just the final three characters and test % 8 == 0; this respects the no-full-conversion constraint. A streaming Horner's-method remainder (running r = (r*10 + digit) % 8) is the O(n)/O(1)-space alternative that avoids large integers entirely and generalizes to any divisor. Both correctly handle leading zeros and strings shorter than three digits.

Key idea (divisibility rule for 8)

A number is divisible by 8 if and only if the number formed by its last three digits is divisible by 8. This works because 1000 = 8 × 125, so every digit at position 1000 or higher contributes a multiple of 1000 (hence a multiple of 8) and can be ignored. We never need to read more than the final three characters of the string.

The usual cases:

  • If len(s) <= 3: parse the whole (short) string as an integer and check % 8 == 0. This is safe — it's at most a 3-digit number.
  • Otherwise: take the last 3 characters, parse just those (a tiny integer in 0..999), and check divisibility by 8. Leading zeros in that 3-char slice are harmless because int("016") == 16.

We deliberately parse only up to 3 characters, so we never violate the "don't convert the full string" constraint, and the work is O(1) regardless of the input length (up to 10^6 digits).

Python
def divisible_by_8(s: str) -> bool:
    # Only the last (up to) 3 digits matter, because 1000 is divisible by 8.
    last3 = s[-3:]
    return int(last3) % 8 == 0

s[-3:] already handles strings shorter than 3 characters (it just returns the whole string), and int("016") correctly yields 16, so leading zeros need no special handling.

Alternative: streaming modular arithmetic (no slicing, no large int)

If the interviewer wants you to avoid even constructing a 3-character integer, process the string left to right keeping a running remainder mod 8. Horner's method keeps the accumulator small:

def divisible_by_8(s: str) -> bool:
    r = 0
    for ch in s:
        r = (r * 10 + (ord(ch) - ord('0'))) % 8
    return r == 0

This is O(n) time, O(1) space, and never forms a big integer. The last-three-digits version is preferred when allowed because it is O(1), but the streaming version generalizes to any divisor and is good to mention.

Worked examples
  • "16" → 16 % 8 == 0 → True
  • "123" → 123 % 8 == 3 → False
  • "1000" → last 3 = "000" → 0 % 8 == 0 → True
  • "00016" → last 3 = "016" → 16 % 8 == 0 → True