title: Check if Numbers Are Ascending in a Sentence
slug: check-if-numbers-are-ascending-in-a-sentence
difficulty: easy
leetcode_id: 2042
leetcode_url: https://leetcode.com/problems/check-if-numbers-are-ascending-in-a-sentence/
categories:
  - strings
patterns:
  - two-pointers

description: |
  A sentence is a list of **tokens** separated by a **single** space with no leading or trailing spaces. Every token is either a **positive number** consisting of digits `0-9` with no leading zeros, or a **word** consisting of lowercase English letters.

  For example, `"a puppy has 2 eyes 4 legs"` is a sentence with seven tokens: `"2"` and `"4"` are numbers and the other tokens such as `"puppy"` are words.

  Given a string `s` representing a sentence, you need to check if **all** the numbers in `s` are **strictly increasing** from left to right (i.e., other than the last number, **each** number is **strictly smaller** than the number on its **right** in `s`).

  Return `true` if so, or `false` otherwise.

constraints: |
  - `3 <= s.length <= 200`
  - `s` consists of lowercase English letters, spaces, and digits from `0` to `9`, inclusive
  - The number of tokens in `s` is between `2` and `100`, inclusive
  - The tokens in `s` are separated by a single space
  - There are at least **two** numbers in `s`
  - Each number in `s` is a **positive** number **less** than `100`, with no leading zeros
  - `s` contains no leading or trailing spaces

examples:
  - input: 's = "1 box has 3 blue 4 red 6 green and 12 yellow marbles"'
    output: "true"
    explanation: "The numbers in s are: 1, 3, 4, 6, 12. They are strictly increasing from left to right: 1 < 3 < 4 < 6 < 12."
  - input: 's = "hello world 5 x 5"'
    output: "false"
    explanation: "The numbers in s are: 5, 5. They are not strictly increasing."
  - input: 's = "sunset is at 7 51 pm overnight lows will be in the low 50 and 60 s"'
    output: "false"
    explanation: "The numbers in s are: 7, 51, 50, 60. They are not strictly increasing."

explanation:
  intuition: |
    Imagine reading a sentence aloud and keeping mental track of any numbers you encounter. Each time you see a new number, you compare it to the last number you remember. If it's bigger, you update your memory with this new number and continue. If it's smaller or equal, you know the sequence isn't strictly increasing.

    The key insight is that we don't need to store all the numbers — we only need to remember the **most recent number** we've seen. This is because "strictly increasing" is a *transitive* property: if each number is greater than the one before it, then all numbers form an increasing sequence.

    Think of it like climbing stairs: you only need to check that each step is higher than the one you're currently on, not every step you've already climbed.

  approach: |
    We solve this using a **Single Pass with Token Extraction**:

    **Step 1: Split the sentence into tokens**

    - Use the space character as a delimiter to split the sentence
    - This gives us an array of words and numbers as strings

    &nbsp;

    **Step 2: Initialise a tracker for the previous number**

    - `prev_num`: Set to `0` initially (since all numbers are positive, any valid number will be greater)

    &nbsp;

    **Step 3: Iterate through each token**

    - For each token, check if it consists entirely of digits (using `isdigit()`)
    - If it's a number:
      - Convert the string to an integer
      - Compare it with `prev_num`
      - If `current_num <= prev_num`, return `false` immediately
      - Otherwise, update `prev_num = current_num` and continue

    &nbsp;

    **Step 4: Return the result**

    - If we complete the iteration without finding a violation, return `true`

  common_pitfalls:
    - title: Checking for Non-Strict Increase
      description: |
        The problem requires **strictly increasing** numbers, meaning each number must be **greater than** (not equal to) the previous one.

        With `s = "hello world 5 x 5"`, the numbers are 5 and 5. Since `5 == 5` (not `5 > 5`), this should return `false`.

        Make sure your comparison uses `<=` to catch equal values as violations, not just `<`.
      wrong_approach: "Only checking if current_num < prev_num"
      correct_approach: "Checking if current_num <= prev_num"

    - title: String Comparison Instead of Integer Comparison
      description: |
        When comparing numbers, you must convert strings to integers first. String comparison uses lexicographic order, which doesn't match numeric order.

        For example, `"9" > "12"` is `true` in string comparison (because '9' comes after '1' alphabetically), but numerically `9 < 12`.

        Always convert to integers before comparing: `int("9") < int("12")` correctly gives `true`.
      wrong_approach: 'Comparing tokens directly as strings: "9" > "12"'
      correct_approach: "Converting to int first: int(token)"

    - title: Missing the First or Last Number
      description: |
        Off-by-one errors can occur if you don't properly handle the initial state or the iteration bounds.

        Setting `prev_num = 0` works because all valid numbers in this problem are positive (≥ 1). Any valid first number will be greater than 0.

        If the problem allowed 0 as a valid number, you'd need a different sentinel value like `-1` or use a flag to track if you've seen the first number.

  key_takeaways:
    - "**Single-pass pattern**: Track just what you need (the previous number) rather than storing all numbers"
    - "**Sentinel values**: Using `0` as `prev_num` works because valid numbers are always positive — this avoids special-casing the first number"
    - "**String vs numeric comparison**: Always convert strings to integers when comparing numerical values"
    - "**Strictly vs non-strictly increasing**: Pay close attention to whether `>` or `>=` is required"

  time_complexity: "O(n). We iterate through each character of the string once during splitting and token processing, where `n` is the length of the string."
  space_complexity: "O(n). The split operation creates an array of tokens that in the worst case contains O(n) characters total."

solutions:
  - approach_name: Single Pass with Split
    is_optimal: true
    code: |
      def are_numbers_ascending(s: str) -> bool:
          # Split sentence into individual tokens
          tokens = s.split()

          # Track the previous number seen (0 works since all numbers are positive)
          prev_num = 0

          for token in tokens:
              # Check if this token is a number (all digits)
              if token.isdigit():
                  # Convert to integer for proper numeric comparison
                  current_num = int(token)

                  # Must be strictly greater than previous number
                  if current_num <= prev_num:
                      return False

                  # Update tracker for next comparison
                  prev_num = current_num

          # All numbers were strictly increasing
          return True
    explanation: |
      **Time Complexity:** O(n) — We split the string once and iterate through each token.

      **Space Complexity:** O(n) — The split creates a list of tokens.

      This solution leverages Python's `split()` to tokenise the sentence, then checks each token. Using `isdigit()` cleanly identifies numbers, and comparing integers ensures correct numeric ordering.

  - approach_name: Character-by-Character Parsing
    is_optimal: false
    code: |
      def are_numbers_ascending(s: str) -> bool:
          prev_num = 0
          i = 0
          n = len(s)

          while i < n:
              # Skip non-digit characters
              if not s[i].isdigit():
                  i += 1
                  continue

              # Found start of a number - extract all digits
              current_num = 0
              while i < n and s[i].isdigit():
                  # Build number digit by digit
                  current_num = current_num * 10 + int(s[i])
                  i += 1

              # Check if strictly increasing
              if current_num <= prev_num:
                  return False

              prev_num = current_num

          return True
    explanation: |
      **Time Complexity:** O(n) — Single pass through the string.

      **Space Complexity:** O(1) — No extra data structures, just integer variables.

      This approach manually parses the string character by character, building numbers digit by digit. While it uses constant space (no split array), it's more verbose and error-prone. The split approach is preferred for readability unless memory is extremely constrained.
