Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions problems/3871-count-commas-in-range-ii/analysis.md
Original file line number Diff line number Diff line change
@@ -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.
56 changes: 56 additions & 0 deletions problems/3871-count-commas-in-range-ii/problem.md
Original file line number Diff line number Diff line change
@@ -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`
29 changes: 29 additions & 0 deletions problems/3871-count-commas-in-range-ii/solution_daily_20260909.go
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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)
}
}
}