diff --git a/problems/1291-sequential-digits/analysis_daily_20260713.md b/problems/1291-sequential-digits/analysis_daily_20260713.md new file mode 100644 index 0000000..7bf6ebb --- /dev/null +++ b/problems/1291-sequential-digits/analysis_daily_20260713.md @@ -0,0 +1,58 @@ +# 1291. Sequential Digits + +[LeetCode Link](https://leetcode.com/problems/sequential-digits/) + +Difficulty: Medium +Topics: Enumeration +Acceptance Rate: 66.0% + +## Hints + +### Hint 1 + +Before reaching for a data structure, ask a smaller question: *how many* integers with sequential digits even exist? A number that starts at some digit and increases by one each step is completely determined by two things — where it starts and how long it is. That severely limits the possibilities. Think about counting the whole universe of valid numbers rather than scanning every number in `[low, high]`. + +### Hint 2 + +The range can be as large as `10^9`, so iterating from `low` to `high` and checking each number is far too slow. Instead, *generate* only the numbers that qualify. Every sequential-digit number is a contiguous substring of a single fixed string. What is that string, and how can you slide a window across it? + +### Hint 3 + +The key insight: every sequential-digit number is a substring of `"123456789"`. There are only 36 such substrings of length ≥ 2. Slide a window of each possible length (2 through 9) across `"123456789"`, convert each window into an integer, and keep the ones that fall inside `[low, high]`. If you enumerate by increasing length, and within each length from left to right, the results come out already sorted. + +## Approach + +The whole problem hinges on one observation: a number has sequential digits exactly when its digit string is a contiguous slice of `"123456789"`. For example `345` is the slice `"345"`, and `6789` is the slice `"6789"`. No sequential-digit number can contain a `0` (there is nothing before `1`), and none can wrap past `9`, so this single string captures every possibility. + +That means the entire universe of sequential-digit numbers is tiny and fixed, independent of the input: + +- Length 2: `12, 23, 34, 45, 56, 67, 78, 89` +- Length 3: `123, 234, ..., 789` +- ... +- Length 9: `123456789` + +The algorithm: + +1. Let `digits = "123456789"`. +2. For each window `length` from `2` to `9`: + - For each starting index `start` such that the window `[start, start+length)` fits inside the string: + - Build the integer by folding the window's characters: `num = num*10 + (digits[i] - '0')`. + - If `low <= num <= high`, append it to the result. +3. Return the result. + +Because we iterate length ascending (shorter numbers are always numerically smaller) and, within a length, left-to-right (larger starting digit means a larger number), the output is naturally in sorted order. A defensive `sort.Ints` is included but is not strictly required. + +**Walkthrough for `low = 100, high = 300`:** Length-2 windows produce `12..89`, all below `100`, so none qualify. Length-3 windows produce `123, 234, 345, ...`; `123` and `234` are in `[100, 300]`, but `345` and beyond exceed `300`. Length-4+ numbers are all `≥ 1234 > 300`. Result: `[123, 234]`. ✅ + +## Complexity Analysis + +Time Complexity: O(1) — the number of candidate substrings of `"123456789"` is a fixed constant (36 numbers of length ≥ 2), independent of `low` and `high`. Building each number costs at most 9 steps. The optional sort is over ≤ 36 elements, also constant. + +Space Complexity: O(1) — aside from the output list, only a few scalar variables are used. The output itself holds at most 36 integers. + +## Edge Cases + +- **No numbers in range** (e.g. `low = 140, high = 150`): No sequential-digit number lands in this window, so the answer is an empty list. The generate-and-filter approach handles this naturally by simply appending nothing. +- **Single valid number** (e.g. `low = 123, high = 123`): The range collapses to one value; the inclusive bounds `low <= num <= high` must both be non-strict so the endpoint is captured. +- **Boundary around a length change** (e.g. `low = 58, high = 155`): The valid numbers straddle two-digit and three-digit results (`67, 78, 89, 123`), confirming that mixing lengths still yields correctly sorted output. +- **Upper limit `10^9`**: The largest sequential-digit number is `123456789` (9 digits), which is less than `10^9` (10 digits). So a range like `low = high = 10^9` yields an empty list — make sure the loop never tries a length beyond 9. diff --git a/problems/1291-sequential-digits/problem.md b/problems/1291-sequential-digits/problem.md new file mode 100644 index 0000000..4fcb54b --- /dev/null +++ b/problems/1291-sequential-digits/problem.md @@ -0,0 +1,43 @@ +--- +number: "1291" +frontend_id: "1291" +title: "Sequential Digits" +slug: "sequential-digits" +difficulty: "Medium" +topics: + - "Enumeration" +acceptance_rate: 6597.4 +is_premium: false +created_at: "2026-07-13T04:07:57.382751+00:00" +fetched_at: "2026-07-13T04:07:57.382751+00:00" +link: "https://leetcode.com/problems/sequential-digits/" +date: "2026-07-13" +--- + +# 1291. Sequential Digits + +An integer has _sequential digits_ if and only if each digit in the number is one more than the previous digit. + +Return a **sorted** list of all the integers in the range `[low, high]` inclusive that have sequential digits. + + + +**Example 1:** + + + **Input:** low = 100, high = 300 + **Output:** [123,234] + + +**Example 2:** + + + **Input:** low = 1000, high = 13000 + **Output:** [1234,2345,3456,4567,5678,6789,12345] + + + + +**Constraints:** + + * `10 <= low <= high <= 10^9` diff --git a/problems/1291-sequential-digits/solution_daily_20260713.go b/problems/1291-sequential-digits/solution_daily_20260713.go new file mode 100644 index 0000000..309f033 --- /dev/null +++ b/problems/1291-sequential-digits/solution_daily_20260713.go @@ -0,0 +1,31 @@ +package main + +import "sort" + +// Sequential Digits (LeetCode 1291) +// +// Every number with sequential digits is a contiguous substring of the fixed +// string "123456789". We slide a window of each possible length (2..9) across +// that string, turn each window into an integer, and keep the ones that fall +// inside [low, high]. This enumerates the entire (tiny, constant-size) universe +// of candidates instead of scanning the potentially huge [low, high] range. +func sequentialDigits(low int, high int) []int { + const digits = "123456789" + + result := []int{} + for length := 2; length <= len(digits); length++ { + for start := 0; start+length <= len(digits); start++ { + num := 0 + for i := start; i < start+length; i++ { + num = num*10 + int(digits[i]-'0') + } + if num >= low && num <= high { + result = append(result, num) + } + } + } + + // The generation order already yields sorted output, but sort defensively. + sort.Ints(result) + return result +} diff --git a/problems/1291-sequential-digits/solution_daily_20260713_test.go b/problems/1291-sequential-digits/solution_daily_20260713_test.go new file mode 100644 index 0000000..d8b5afa --- /dev/null +++ b/problems/1291-sequential-digits/solution_daily_20260713_test.go @@ -0,0 +1,61 @@ +package main + +import ( + "reflect" + "testing" +) + +func TestSolution(t *testing.T) { + tests := []struct { + name string + low int + high int + expected []int + }{ + { + name: "example 1: range 100 to 300", + low: 100, + high: 300, + expected: []int{123, 234}, + }, + { + name: "example 2: range 1000 to 13000", + low: 1000, + high: 13000, + expected: []int{1234, 2345, 3456, 4567, 5678, 6789, 12345}, + }, + { + name: "edge case: no sequential digits in range", + low: 140, + high: 150, + expected: []int{}, + }, + { + name: "edge case: single value range with one match", + low: 123, + high: 123, + expected: []int{123}, + }, + { + name: "edge case: boundary spanning two- and three-digit numbers", + low: 58, + high: 155, + expected: []int{67, 78, 89, 123}, + }, + { + name: "edge case: upper limit 10^9 has no 10-digit sequential number", + low: 1000000000, + high: 1000000000, + expected: []int{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := sequentialDigits(tt.low, tt.high) + if !reflect.DeepEqual(result, tt.expected) { + t.Errorf("sequentialDigits(%d, %d) = %v, want %v", tt.low, tt.high, result, tt.expected) + } + }) + } +}