PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates parsing and numeric manipulation skills, specifically implementing rounding rules for numeric strings and handling decimals, significant digits, and precision edge cases.

  • Medium
  • Pinterest
  • Coding & Algorithms
  • Software Engineer

Round numeric string values

Company: Pinterest

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

##### Question Given a numeric string, implement rounding to the nearest integer (e.g., '3.5' → '4', '100.01' → '100'). Follow-up: round to the last significant digit (e.g., 124900 → 125000, 12.49 → 12. 5).

Quick Answer: This question evaluates parsing and numeric manipulation skills, specifically implementing rounding rules for numeric strings and handling decimals, significant digits, and precision edge cases.

Implement a function round_numeric_string(s, mode) that rounds a base-10 numeric string s according to mode. If mode == "integer", round to the nearest integer with ties at exactly 0.5 rounded away from zero (e.g., "3.5" -> "4", "-2.5" -> "-3"). If mode == "last_sig_digit", reduce precision by one significant digit using half-up rounding: identify the first and last non-zero digits of s (ignoring leading zeros and the decimal point). If there are at least two significant digits, drop the last significant digit by rounding the preceding digit, then zero-out less significant places (e.g., "124900" -> "125000", "12.49" -> "12.5"). If there is only one significant digit, return the canonical form of s. The result must be minimally formatted: no leading zeros (except a single zero before the decimal point), no trailing zeros after the decimal point, and no trailing decimal point. Return "0" instead of "-0". The input s may include an optional leading sign and at most one decimal point; no exponent notation.

Constraints

  • 1 <= len(s) <= 100000
  • s matches the regex ^[+-]?\d+(\.\d+)?$ (no exponent, no separators)
  • mode is either "integer" or "last_sig_digit"
  • Rounding rule for mode="integer": nearest integer, ties at .5 round away from zero
  • Rounding rule for mode="last_sig_digit": half-up on the last significant digit; if only one significant digit exists, return canonical s
  • Output formatting: remove leading zeros (keep one before '.'), remove trailing zeros after '.', remove trailing '.', never return "-0"

Examples

Input:

Expected Output: 4

Input:

Expected Output: 100

Input:

Expected Output: -3

Input:

Expected Output: 125000

Input:

Expected Output: 12

Input:

Expected Output: 0.006

Input:

Expected Output: 10

Input:

Expected Output: 12.5

Solution

def round_numeric_string(s: str, mode: str) -> str:
    s = s.strip()
    if not s:
        return "0"

    # Parse sign
    sign = 1
    if s[0] == '+':
        s = s[1:]
    elif s[0] == '-':
        sign = -1
        s = s[1:]

    # Split into integer and fractional parts
    if '.' in s:
        a, b = s.split('.', 1)
    else:
        a, b = s, ""

    if a == "":
        a = "0"  # ensure at least one digit before decimal for indexing

    # Build digits and decimal point index
    digits = [ord(c) - 48 for c in (a + b)]
    point = len(a)

    def format_result(digs, p):
        left = ''.join(str(d) for d in digs[:p]).lstrip('0')
        if left == "":
            left = "0"
        right = ''.join(str(d) for d in digs[p:]).rstrip('0')
        if right:
            return left + "." + right
        else:
            return left

    def apply_sign(res: str) -> str:
        if res == "0":
            return "0"
        return ("-" + res) if sign < 0 else res

    def add_one(digs):
        k = len(digs) - 1
        while k >= 0:
            v = digs[k] + 1
            if v < 10:
                digs[k] = v
                return digs
            digs[k] = 0
            k -= 1
        return [1] + digs

    if mode == "integer":
        # No fractional part
        if point >= len(digits):
            res = ''.join(str(d) for d in digits[:point]).lstrip('0') or "0"
            return apply_sign(res)
        # Fractional present
        round_up = digits[point] >= 5  # ties and larger go up (away from zero)
        int_digs = digits[:point]
        if not int_digs:
            int_digs = [0]
        if round_up:
            int_digs = add_one(int_digs[:])
        res = ''.join(str(d) for d in int_digs).lstrip('0') or "0"
        return apply_sign(res)

    elif mode == "last_sig_digit":
        # Find first and last non-zero digit
        i = None
        for idx, d in enumerate(digits):
            if d != 0:
                i = idx
                break
        if i is None:
            return "0"
        j = None
        for idx in range(len(digits) - 1, -1, -1):
            if digits[idx] != 0:
                j = idx
                break
        # Only one significant digit: return canonical form
        if i == j:
            res = format_result(digits, point)
            return apply_sign(res)
        # Reduce precision by one significant digit
        last_keep = j - 1
        if digits[j] >= 5:
            k = last_keep
            carry = 1
            while k >= 0 and carry:
                nv = digits[k] + carry
                if nv < 10:
                    digits[k] = nv
                    carry = 0
                else:
                    digits[k] = 0
                    k -= 1
            if carry:
                digits.insert(0, 1)
                point += 1
                last_keep += 1
        for idx in range(last_keep + 1, len(digits)):
            digits[idx] = 0
        res = format_result(digits, point)
        return apply_sign(res)

    else:
        # Fallback to integer rounding if mode is invalid
        round_up = False
        if point < len(digits):
            round_up = digits[point] >= 5
        int_digs = digits[:point] if point > 0 else [0]
        if round_up:
            if not int_digs:
                int_digs = [0]
            k = len(int_digs) - 1
            carry = 1
            while k >= 0 and carry:
                nv = int_digs[k] + carry
                if nv < 10:
                    int_digs[k] = nv
                    carry = 0
                else:
                    int_digs[k] = 0
                    k -= 1
            if carry:
                int_digs = [1] + int_digs
        res = ''.join(str(d) for d in int_digs).lstrip('0') or "0"
        if res == "0":
            return "0"
        return ("-" + res) if sign < 0 else res
Explanation
We avoid floating-point arithmetic by operating on the string's digits directly. We parse the sign, collect all digits into an array, and remember the decimal point index. For mode="integer", we inspect only the first digit after the decimal to decide whether the fractional part is < 0.5 or >= 0.5; on >= 0.5 we increment the integer digits (away from zero for negatives as well). For mode="last_sig_digit", we find the first and last non-zero digits to determine the current significant-digit span. If there is just one significant digit, we return the canonical form. Otherwise, we round the digit just before the last non-zero and propagate carry left as needed, then zero out less significant places (which may introduce carry to a new most significant digit). Finally, we format by stripping leading zeros in the integer part (keeping one zero), removing trailing zeros from the fractional part, and omitting the decimal point if there is no fractional part. We also normalize -0 to 0.

Time complexity: O(n). Space complexity: O(n).

Hints

  1. Avoid floating-point; work directly on the string digits.
  2. For integer rounding, comparing only the first digit after the decimal to 5 suffices to decide <0.5 vs >=0.5.
  3. Represent the number as a digit array plus the decimal index. For last_sig_digit, find the first and last non-zero positions.
  4. When reducing precision by one significant digit, round the digit before the last non-zero and propagate carry left; then zero-out all less significant digits.
  5. Normalize the final string: strip leading zeros in the integer part (keep one zero), strip trailing zeros in the fractional part, and omit the decimal point if the fractional part becomes empty.
Last updated: Mar 29, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Maximize Boxes Stored Through One Entrance - Pinterest (medium)
  • Solve Multiple Coding Interview Problems - Pinterest (medium)
  • Implement a Sparse Matrix Class - Pinterest (medium)
  • Assign Pins to Shortest Columns - Pinterest (medium)
  • Design Hierarchical Permission Checks - Pinterest (medium)