Facebook Pixel

2042. Check if Numbers Are Ascending in a Sentence

EasyString
Leetcode Link

Problem Description

You are given a string s that represents a sentence. A sentence consists of tokens separated by single spaces, with no leading or trailing spaces. Each token is either:

  • A positive number made up of digits 0-9 with no leading zeros
  • A word made up of lowercase English letters

For example, "a puppy has 2 eyes 4 legs" contains 7 tokens where "2" and "4" are numbers, while "a", "puppy", "has", "eyes", and "legs" are words.

Your task is to check if all the numbers in the sentence appear in strictly increasing order from left to right. This means each number must be strictly smaller than the next number that appears after it in the sentence.

Return true if all numbers are in strictly increasing order, or false otherwise.

The solution works by:

  1. Splitting the string s into individual tokens using spaces
  2. For each token, checking if it starts with a digit (indicating it's a number)
  3. If it's a number, converting it to an integer and comparing with the previous number
  4. If any number is not greater than the previous one, returning false
  5. If all numbers maintain strict increasing order, returning true

The key insight is using the isdigit() method to identify numbers and maintaining a pre variable to track the previous number for comparison. The walrus operator := is used to assign and use the current number value in a single expression.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The problem asks us to verify if numbers in a sentence follow a strictly increasing pattern. The natural approach is to process the sentence sequentially from left to right, just as we would read it.

Since we need to compare consecutive numbers, we need to:

  1. Extract all numbers from the sentence in the order they appear
  2. Compare each number with the one before it

The key observation is that we don't need to store all numbers - we only need to remember the last number we encountered to compare with the current one. This is because "strictly increasing" means each number only needs to be greater than the immediate previous number.

To identify whether a token is a number or a word, we can check if its first character is a digit. Since the problem guarantees that numbers have no leading zeros (except for the number 0 itself), checking token[0].isdigit() is sufficient to determine if a token is a number.

The algorithm naturally follows a single-pass pattern:

  • Initialize a variable pre to track the previous number (starting at 0 since all numbers are positive)
  • Split the sentence into tokens
  • For each token that's a number, check if it's greater than pre
  • If we find any number that's not greater than the previous one, we can immediately return false
  • Update pre to the current number and continue
  • If we process all numbers without finding a violation, return true

This greedy approach works because the strictly increasing property is transitive - if a < b and b < c, then a < c. So we only need to check adjacent pairs of numbers in sequence.

Solution Approach

The implementation follows a straightforward simulation approach by processing the sentence token by token.

Step-by-step implementation:

  1. Initialize tracking variable: Start with pre = 0 to keep track of the previous number. We use 0 as the initial value since all numbers in the sentence are positive integers, ensuring the first number will always be greater than pre.

  2. Split the sentence into tokens: Use s.split() to break the sentence into individual tokens separated by spaces. This handles multiple spaces automatically and returns a list of non-empty tokens.

  3. Process each token: Iterate through each token t in the split sentence:

    • Check if the token is a number by testing if its first character is a digit: t[0].isdigit()
    • If it's a number:
      • Convert it to an integer: int(t)
      • Compare with the previous number
      • If the current number is less than or equal to the previous (cur <= pre), return False immediately
      • Otherwise, update pre to the current number for the next comparison
  4. Return result: If we complete the iteration without finding any violations, return True.

Key implementation details:

  • The walrus operator := is used to assign and use the converted integer value in one expression: if (cur := int(t)) <= pre:
  • Early termination: As soon as we find a number that's not strictly greater than the previous one, we return False without checking remaining tokens
  • We only track numbers and completely ignore word tokens, as they don't affect the strictly increasing property

Time Complexity: O(n) where n is the length of the string, as we process each character once during splitting and iteration.

Space Complexity: O(m) where m is the number of tokens, needed to store the split result.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with the example: "hello world 5 x 9 y 27"

Initial State:

  • pre = 0 (tracks the previous number)
  • Split the string: ["hello", "world", "5", "x", "9", "y", "27"]

Processing each token:

  1. Token: "hello"

    • Check: "hello"[0].isdigit()"h".isdigit()False
    • This is a word, skip it
    • pre remains 0
  2. Token: "world"

    • Check: "world"[0].isdigit()"w".isdigit()False
    • This is a word, skip it
    • pre remains 0
  3. Token: "5"

    • Check: "5"[0].isdigit()True
    • This is a number!
    • Convert: cur = int("5") = 5
    • Compare: Is 5 <= 0? → False (5 > 0, so it's good)
    • Update: pre = 5
  4. Token: "x"

    • Check: "x"[0].isdigit()False
    • This is a word, skip it
    • pre remains 5
  5. Token: "9"

    • Check: "9"[0].isdigit()True
    • This is a number!
    • Convert: cur = int("9") = 9
    • Compare: Is 9 <= 5? → False (9 > 5, so it's good)
    • Update: pre = 9
  6. Token: "y"

    • Check: "y"[0].isdigit()False
    • This is a word, skip it
    • pre remains 9
  7. Token: "27"

    • Check: "27"[0].isdigit()"2".isdigit()True
    • This is a number!
    • Convert: cur = int("27") = 27
    • Compare: Is 27 <= 9? → False (27 > 9, so it's good)
    • Update: pre = 27

Result: All numbers (5, 9, 27) are in strictly increasing order, so return True.

Counter-example: If the sentence was "hello 5 x 3 y 27", the algorithm would:

  • Process "5": pre = 5
  • Process "3": Compare 3 <= 5? → True (violation!)
  • Immediately return False without checking "27"

Solution Implementation

1class Solution:
2    def areNumbersAscending(self, s: str) -> bool:
3        """
4        Check if all numbers in the string appear in strictly ascending order.
5      
6        Args:
7            s: Input string containing words and numbers separated by spaces
8          
9        Returns:
10            True if numbers are in strictly ascending order, False otherwise
11        """
12        # Initialize previous number to track ascending order
13        previous_number = 0
14      
15        # Split the string into tokens by whitespace
16        tokens = s.split()
17      
18        # Iterate through each token
19        for token in tokens:
20            # Check if the token is a number (starts with a digit)
21            if token[0].isdigit():
22                # Convert token to integer
23                current_number = int(token)
24              
25                # Check if current number is not strictly greater than previous
26                if current_number <= previous_number:
27                    return False
28              
29                # Update previous number for next comparison
30                previous_number = current_number
31      
32        # All numbers are in strictly ascending order
33        return True
34
1class Solution {
2    /**
3     * Checks if all numbers in a string are in strictly ascending order.
4     * 
5     * @param s the input string containing words and numbers separated by spaces
6     * @return true if all numbers are in strictly ascending order, false otherwise
7     */
8    public boolean areNumbersAscending(String s) {
9        // Track the previous number to compare with current number
10        int previousNumber = 0;
11      
12        // Split the string by spaces and iterate through each token
13        for (String token : s.split(" ")) {
14            // Check if the token is a number by examining if first character is a digit
15            if (token.charAt(0) >= '0' && token.charAt(0) <= '9') {
16                // Parse the current token as an integer
17                int currentNumber = Integer.parseInt(token);
18              
19                // Check if numbers are in strictly ascending order
20                if (previousNumber >= currentNumber) {
21                    return false;
22                }
23              
24                // Update previous number for next comparison
25                previousNumber = currentNumber;
26            }
27        }
28      
29        // All numbers are in strictly ascending order
30        return true;
31    }
32}
33
1class Solution {
2public:
3    bool areNumbersAscending(string s) {
4        int previousNumber = 0;  // Track the previous number for comparison
5        istringstream inputStream(s);  // Create a string stream to parse words
6        string word;
7      
8        // Read each word from the string stream
9        while (inputStream >> word) {
10            // Check if the current word is a number (starts with a digit)
11            if (isdigit(word[0])) {
12                int currentNumber = stoi(word);  // Convert string to integer
13              
14                // Check if numbers are in strictly ascending order
15                if (previousNumber >= currentNumber) {
16                    return false;  // Not strictly ascending
17                }
18              
19                previousNumber = currentNumber;  // Update previous number
20            }
21        }
22      
23        return true;  // All numbers are in strictly ascending order
24    }
25};
26
1/**
2 * Checks if all numbers in a string are in strictly ascending order
3 * @param s - Input string containing words and numbers separated by spaces
4 * @returns true if all numbers are in strictly ascending order, false otherwise
5 */
6function areNumbersAscending(s: string): boolean {
7    // Initialize previous number to track ascending order
8    let previousNumber: number = -1;
9  
10    // Split the string by spaces and iterate through each token
11    for (const token of s.split(' ')) {
12        // Check if the token starts with a digit (0-9)
13        if (token[0] >= '0' && token[0] <= '9') {
14            // Convert the token to a number
15            const currentNumber: number = Number(token);
16          
17            // Check if current number is not greater than previous number
18            if (currentNumber <= previousNumber) {
19                return false;
20            }
21          
22            // Update previous number for next comparison
23            previousNumber = currentNumber;
24        }
25    }
26  
27    // All numbers are in strictly ascending order
28    return true;
29}
30

Time and Space Complexity

The time complexity is O(n), where n is the length of the string s. This is because:

  • The s.split() operation needs to traverse the entire string once to identify word boundaries, which takes O(n) time
  • The iteration through the split tokens also takes O(n) time in the worst case (when processing all characters)
  • For each token that is a number, int(t) conversion takes O(k) time where k is the length of the number, but since all number lengths sum up to at most n, the total conversion time is still O(n)

The space complexity is O(n), where n is the length of the string s. This is because:

  • The s.split() method creates a new list containing all the tokens from the string, which in the worst case could be O(n) space (e.g., when the string is "1 2 3 4 5...")
  • The individual tokens themselves also consume space proportional to the original string length
  • The variables pre and cur only use O(1) additional space

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Assuming tokens are always single characters

A common mistake is checking only token[0].isdigit() without considering that the entire token should be validated as a number. While this works for the given problem constraints (numbers have no leading zeros), it could fail if the problem allowed mixed tokens like "2abc" or if you need to handle edge cases.

Pitfall Example:

# This would incorrectly identify "2abc" as a number
if token[0].isdigit():
    current_number = int(token)  # Would crash with ValueError

Solution: Use token.isdigit() to check if the entire token consists of digits:

if token.isdigit():
    current_number = int(token)

2. Not handling empty strings or edge cases

The code assumes the input is well-formed, but doesn't explicitly handle empty strings or tokens.

Pitfall Example:

# Would crash on empty string
s = ""
tokens = s.split()  # Returns []
for token in tokens:
    if token[0].isdigit():  # No issue here since loop doesn't execute

Solution: Add validation for empty or malformed tokens:

for token in tokens:
    if token and token[0].isdigit():  # Check token is not empty
        current_number = int(token)

3. Using wrong initial value for previous_number

Setting previous_number to a non-zero value could cause incorrect results.

Pitfall Example:

previous_number = 10  # Wrong initial value
# String "5 is less than 10" would incorrectly return False

Solution: Always initialize to 0 or negative infinity for positive numbers:

previous_number = 0  # Correct for positive numbers
# or
previous_number = float('-inf')  # Works for any numbers

4. Confusing strictly increasing with non-decreasing

The problem requires strictly increasing order (each number must be greater than the previous), not just non-decreasing (greater than or equal).

Pitfall Example:

# Wrong: allows equal numbers
if current_number < previous_number:  # Should be <=
    return False

Solution: Use <= to ensure strict inequality:

if current_number <= previous_number:  # Correct
    return False
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which algorithm should you use to find a node that is close to the root of the tree?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More