From bbbafca4d4eee09b5c2d8889577fd3c5c99f9dac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 9 Sep 2026 04:59:52 +0000 Subject: [PATCH] feat: add solution for 3871. Count Commas in Range II --- .../3871-count-commas-in-range-ii/analysis.md | 129 ++++++++++++++++++ .../3871-count-commas-in-range-ii/problem.md | 56 ++++++++ .../solution_daily_20260909.go | 29 ++++ .../solution_daily_20260909_test.go | 54 ++++++++ 4 files changed, 268 insertions(+) create mode 100644 problems/3871-count-commas-in-range-ii/analysis.md create mode 100644 problems/3871-count-commas-in-range-ii/problem.md create mode 100644 problems/3871-count-commas-in-range-ii/solution_daily_20260909.go create mode 100644 problems/3871-count-commas-in-range-ii/solution_daily_20260909_test.go diff --git a/problems/3871-count-commas-in-range-ii/analysis.md b/problems/3871-count-commas-in-range-ii/analysis.md new file mode 100644 index 0000000..21f862c --- /dev/null +++ b/problems/3871-count-commas-in-range-ii/analysis.md @@ -0,0 +1,129 @@ +# 3871. Count Commas in Range II + +[LeetCode Link](https://leetcode.com/problems/count-commas-in-range-ii/) + +Difficulty: Medium +Topics: Math +Acceptance Rate: 44.7% + +## Hints + +### Hint 1 + +`n` can be as large as `10^15`, so any loop that visits every integer from `1` to `n` +is hopeless. That constraint is the whole hint: the answer has to come from a closed-form +count, not from simulation. Ask yourself what property of a single number decides how many +commas it gets, and whether you can count how many numbers in `[1, n]` share that property +without enumerating them. + +### Hint 2 + +For one number `x` with `d` digits, the comma count is `(d - 1) / 3` (integer division): +4-6 digits get 1 comma, 7-9 digits get 2, and so on. So the total is +`sum over x in [1, n] of (digits(x) - 1) / 3`. + +You could group numbers by digit length — there are `9 * 10^(d-1)` numbers with exactly `d` +digits — and multiply each group size by its comma count. That works, but there is a +reformulation that is even shorter and avoids the "partial last group" bookkeeping. + +### Hint 3 + +Instead of asking "how many commas does each number have," flip it and ask +"how many numbers does each comma position appear in." + +A number gets its **k-th** comma exactly when it has at least `3k + 1` digits, i.e. when +`x >= 10^(3k)`. So the k-th comma contributes one unit for every `x` in `[10^(3k), n]`. + +That turns the whole problem into a sum of at most five terms: + +``` +answer = sum over k >= 1 of max(0, n - 10^(3k) + 1) +``` + +Since `n <= 10^15`, only `k = 1..5` can ever contribute (`10^3, 10^6, 10^9, 10^12, 10^15`). + +## Approach + +The key move is exchanging the order of summation. The naive view is + +``` +answer = Σ_{x=1}^{n} commas(x) +``` + +where `commas(x) = (digits(x) - 1) / 3`. Rewrite `commas(x)` as an indicator sum: + +``` +commas(x) = Σ_{k>=1} [ x has a k-th comma ] +``` + +A number written in standard formatting places a comma after every group of three digits +counted from the right. The first comma appears once the number reaches 4 digits, the +second once it reaches 7 digits, the third at 10 digits, and generally the k-th comma +appears exactly when the number has at least `3k + 1` digits — which is precisely +`x >= 10^(3k)`. + +Substituting and swapping the two sums: + +``` +answer = Σ_{x=1}^{n} Σ_{k>=1} [ x >= 10^(3k) ] + = Σ_{k>=1} Σ_{x=1}^{n} [ x >= 10^(3k) ] + = Σ_{k>=1} |{ x : 10^(3k) <= x <= n }| + = Σ_{k>=1} max(0, n - 10^(3k) + 1) +``` + +Each inner count is just the size of a contiguous integer interval, which is why no +enumeration is needed. The algorithm is then a loop over powers of one thousand: + +1. Start with `total = 0` and `p = 1000`. +2. While `p <= n`, add `n - p + 1` to `total` and multiply `p` by `1000`. +3. Return `total`. + +The loop runs at most 5 times for the given constraints (`1000, 10^6, 10^9, 10^12, 10^15`), +so it is effectively constant time. + +**Worked example, `n = 1002`:** + +- `p = 1000`: `1000 <= 1002`, so add `1002 - 1000 + 1 = 3`. These are `1,000`, `1,001`, + `1,002` — each earning its first comma. +- `p = 1000000`: `1000000 > 1002`, loop ends. +- Total = `3`, matching the expected output. + +**Worked example, `n = 1000002`:** + +- `p = 1000`: add `1000002 - 999 = 999003` (every number from 1000 up gets a first comma). +- `p = 1000000`: add `1000002 - 1000000 + 1 = 3` (the three 7-digit numbers each get a + second comma). +- `p = 10^9`: too big, stop. +- Total = `999006`. + +Multiplying `p` by 1000 each iteration is the natural way to walk the thresholds, but note +the overflow trap discussed below — the loop guard must be written so `p` never has to grow +past a representable value. + +## Complexity Analysis + +Time Complexity: O(log n) — more precisely `O(log_1000 n)`, which is at most 5 iterations +for `n <= 10^15`, so constant in practice. +Space Complexity: O(1) — only a running total and the current power of one thousand. + +## Edge Cases + +- **`n < 1000` (including `n = 1`, the minimum).** No number has four digits, so the loop + body never executes and the answer is `0`. This is Example 2 (`n = 998`) and is the main + reason the `max(0, ...)` / loop guard matters: without it you would add a negative term. +- **`n = 999` vs `n = 1000`.** The boundary where the first comma appears. `999` yields `0`, + `1000` yields exactly `1`. Off-by-one errors here usually come from writing `n - p` + instead of `n - p + 1` (the interval `[p, n]` is inclusive on both ends). +- **`n` exactly equal to a power of one thousand** (`10^6`, `10^9`, ...). The new comma + threshold contributes exactly `1`, not `0`. Using `p <= n` rather than `p < n` is what + gets this right. +- **`n = 10^15`, the maximum.** Five thresholds all contribute, and the answer is + `3998998998999005` — far beyond 32-bit range. The accumulator must be a 64-bit type. +- **Overflow while advancing `p`.** If you multiply `p` by 1000 unconditionally, after the + `10^15` iteration `p` becomes `10^18`, which still fits in `int64` — but one more step + would be `10^21` and would overflow. Guarding the multiplication (or bounding the loop by + a fixed count of five) keeps this safe regardless of how the loop is structured. +- **Numbers with a leading digit group shorter than three** (e.g. `1,000` has a one-digit + lead group). This is not a special case at all under the threshold formulation, which is + a nice sanity check that the reformulation is the right one — the digit-length grouping + approach would need explicit care here. diff --git a/problems/3871-count-commas-in-range-ii/problem.md b/problems/3871-count-commas-in-range-ii/problem.md new file mode 100644 index 0000000..0624335 --- /dev/null +++ b/problems/3871-count-commas-in-range-ii/problem.md @@ -0,0 +1,56 @@ +--- +number: "3871" +frontend_id: "3871" +title: "Count Commas in Range II" +slug: "count-commas-in-range-ii" +difficulty: "Medium" +topics: + - "Math" +acceptance_rate: 4470.3 +is_premium: false +created_at: "2026-09-09T04:57:49.576276+00:00" +fetched_at: "2026-09-09T04:57:49.576276+00:00" +link: "https://leetcode.com/problems/count-commas-in-range-ii/" +date: "2026-09-09" +--- + +# 3871. Count Commas in Range II + +You are given an integer `n`. + +Return the **total** number of commas used when writing all integers from `[1, n]` (inclusive) in **standard** number formatting. + +In **standard** formatting: + + * A comma is inserted after **every three** digits from the right. + * Numbers with **fewer** than 4 digits contain no commas. + + + + + +**Example 1:** + +**Input:** n = 1002 + +**Output:** 3 + +**Explanation:** + +The numbers `"1,000"`, `"1,001"`, and `"1,002"` each contain one comma, giving a total of 3. + +**Example 2:** + +**Input:** n = 998 + +**Output:** 0 + +**Explanation:** + +**​​​​​​​** All numbers from 1 to 998 have fewer than four digits. Therefore, no commas are used. + + + +**Constraints:** + + * `1 <= n <= 1015` diff --git a/problems/3871-count-commas-in-range-ii/solution_daily_20260909.go b/problems/3871-count-commas-in-range-ii/solution_daily_20260909.go new file mode 100644 index 0000000..f1a5d8e --- /dev/null +++ b/problems/3871-count-commas-in-range-ii/solution_daily_20260909.go @@ -0,0 +1,29 @@ +package main + +// 3871. Count Commas in Range II +// +// A number x gets its k-th comma exactly when it has at least 3k+1 digits, +// i.e. when x >= 10^(3k). So instead of summing commas per number, we sum over +// comma positions: the k-th comma contributes one unit for every x in [10^(3k), n]. +// +// answer = sum over k >= 1 of max(0, n - 10^(3k) + 1) +// +// With n <= 10^15 only the thresholds 10^3, 10^6, 10^9, 10^12 and 10^15 can +// contribute, so the loop runs at most five times. +func countCommas(n int64) int64 { + const step = 1000 + + var total int64 + // maxP is the largest threshold we could multiply further without overflowing. + const maxP = int64(1) << 62 + + for p := int64(step); p <= n; { + total += n - p + 1 + if p > maxP/step { + break + } + p *= step + } + + return total +} diff --git a/problems/3871-count-commas-in-range-ii/solution_daily_20260909_test.go b/problems/3871-count-commas-in-range-ii/solution_daily_20260909_test.go new file mode 100644 index 0000000..59e646b --- /dev/null +++ b/problems/3871-count-commas-in-range-ii/solution_daily_20260909_test.go @@ -0,0 +1,54 @@ +package main + +import "testing" + +func TestCountCommas(t *testing.T) { + tests := []struct { + name string + n int64 + expected int64 + }{ + {"example 1: n = 1002, three numbers with one comma each", 1002, 3}, + {"example 2: n = 998, every number has fewer than four digits", 998, 0}, + {"edge case: minimum n = 1", 1, 0}, + {"edge case: n = 999, just below the first comma", 999, 0}, + {"edge case: n = 1000, the very first comma", 1000, 1}, + {"edge case: n = 9999, all four-digit numbers counted", 9999, 9000}, + {"edge case: n = 999999, just below the second comma", 999999, 999000}, + {"edge case: n = 1000000, exact power of one thousand adds one", 1000000, 999002}, + {"edge case: n = 1000002, two thresholds contribute", 1000002, 999006}, + {"edge case: n = 10^12, exact threshold deep in the range", 1000000000000, 2998998999004}, + {"edge case: n = 10^15 - 1, just below the maximum threshold", 999999999999999, 3998998998999000}, + {"edge case: maximum n = 10^15", 1000000000000000, 3998998998999005}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := countCommas(tt.n) + if result != tt.expected { + t.Errorf("countCommas(%d) = %v, want %v", tt.n, result, tt.expected) + } + }) + } +} + +// TestCountCommasAgainstBruteForce cross-checks the closed form against a direct +// per-number count over a small range, where enumeration is still cheap. +func TestCountCommasAgainstBruteForce(t *testing.T) { + digits := func(x int64) int { + d := 0 + for ; x > 0; x /= 10 { + d++ + } + return d + } + + var want int64 + for n := int64(1); n <= 200000; n++ { + want += int64((digits(n) - 1) / 3) + + if got := countCommas(n); got != want { + t.Fatalf("countCommas(%d) = %v, want %v", n, got, want) + } + } +}