title: Append K Integers With Minimal Sum
slug: append-k-integers-with-minimal-sum
difficulty: medium
leetcode_id: 2195
leetcode_url: https://leetcode.com/problems/append-k-integers-with-minimal-sum/
categories:
  - arrays
  - math
  - sorting
patterns:
  - slug: greedy
    is_optimal: true

function_signature: "def min_sum(nums: list[int], k: int) -> int:"

test_cases:
  visible:
    - input: { nums: [1, 4, 25, 10, 25], k: 2 }
      expected: 5
    - input: { nums: [5, 6], k: 6 }
      expected: 25
  hidden:
    - input: { nums: [1], k: 1 }
      expected: 2
    - input: { nums: [1, 2, 3], k: 2 }
      expected: 9
    - input: { nums: [2, 4, 6], k: 3 }
      expected: 6
    - input: { nums: [1000000000], k: 1 }
      expected: 1
    - input: { nums: [1, 2, 3, 4, 5], k: 5 }
      expected: 40
    - input: { nums: [3, 3, 3], k: 4 }
      expected: 12

description: |
  You are given an integer array `nums` and an integer `k`. Append `k` **unique positive** integers that do **not** appear in `nums` to `nums` such that the resulting total sum is **minimum**.

  Return *the sum of the* `k` *integers appended to* `nums`.

constraints: |
  - `1 <= nums.length <= 10^5`
  - `1 <= nums[i] <= 10^9`
  - `1 <= k <= 10^8`

examples:
  - input: "nums = [1,4,25,10,25], k = 2"
    output: "5"
    explanation: "The two unique positive integers that do not appear in nums which we append are 2 and 3. The sum of the two integers appended is 2 + 3 = 5."
  - input: "nums = [5,6], k = 6"
    output: "25"
    explanation: "The six unique positive integers that do not appear in nums which we append are 1, 2, 3, 4, 7, and 8. The sum is 1 + 2 + 3 + 4 + 7 + 8 = 25."

explanation:
  intuition: |
    To minimise the sum, we want to pick the **smallest possible positive integers** that aren't already in `nums`. Imagine counting from 1 upward: 1, 2, 3, 4, ... and skipping any number that already exists in the array.

    The key insight is that we don't need to iterate through each number one by one. Instead, we can use the **arithmetic series formula** to calculate sums of consecutive integers in bulk: the sum of integers from `1` to `n` is `n * (n + 1) / 2`.

    Think of it like filling gaps: if `nums` contains some numbers that "block" certain positions, we need to count how many integers we can pick before hitting a blocker, calculate that sum efficiently, then jump past the blocker and continue.

    By sorting `nums` and processing gaps between consecutive elements, we can quickly determine how many "free" integers exist in each range and compute their sum using the formula.

  approach: |
    We solve this using a **Greedy Gap-Filling Approach**:

    **Step 1: Sort and deduplicate the array**

    - Sort `nums` to process elements in order
    - Remove duplicates since they don't affect which integers are "taken"

    &nbsp;

    **Step 2: Initialise tracking variables**

    - `result`: Accumulates the sum of chosen integers (starts at `0`)
    - `prev`: Tracks the last integer we've considered (starts at `0`, meaning we begin from `1`)

    &nbsp;

    **Step 3: Process each number in the sorted array**

    - For each number `num` in the sorted array, calculate the gap: how many integers exist between `prev + 1` and `num - 1` inclusive
    - The count of available integers in this gap is `num - prev - 1`
    - If the gap has more integers than we still need (`k`), we only take `k` of them
    - Use the arithmetic series formula to add the sum of the integers we take: sum from `prev + 1` to `prev + take` is `take * (2 * prev + take + 1) / 2`
    - Subtract the taken count from `k` and update `prev = num`
    - If `k` reaches `0`, we're done

    &nbsp;

    **Step 4: Handle remaining integers after the array**

    - If `k > 0` after processing all elements, we need `k` more integers starting from `prev + 1`
    - Add the sum of integers from `prev + 1` to `prev + k` using the arithmetic series formula

    &nbsp;

    **Step 5: Return the result**

    - Return the accumulated `result` sum

  common_pitfalls:
    - title: Iterating One-by-One
      description: |
        With `k` up to `10^8`, iterating through each integer individually and checking membership would be far too slow.

        For example, if `nums = [10^9]` and `k = 10^8`, you'd need to check and sum 100 million integers one at a time. This results in **O(k)** operations which causes TLE.

        Instead, use the arithmetic series formula `n * (n + 1) / 2` to calculate sums of ranges in **O(1)** time.
      wrong_approach: "Loop through integers 1, 2, 3, ... checking each"
      correct_approach: "Calculate range sums using arithmetic series formula"

    - title: Not Handling Duplicates
      description: |
        The input array can contain duplicate values (e.g., `[1,4,25,10,25]`). If you don't deduplicate, you might incorrectly count the same "blocked" position multiple times.

        For instance, with `nums = [2, 2, 2]`, the integer `2` only blocks one position, not three. Deduplicating ensures each blocked position is counted exactly once.
      wrong_approach: "Process array with duplicates"
      correct_approach: "Convert to set or deduplicate after sorting"

    - title: Integer Overflow
      description: |
        The sum of `k` integers (where `k` can be `10^8`) starting from 1 is approximately `k * k / 2`, which can exceed `10^16`. In languages with fixed-size integers, this can cause overflow.

        Python handles arbitrary precision integers automatically, but in other languages you'd need to use 64-bit integers (`long long` in C++, `Long` in Java).
      wrong_approach: "Use 32-bit integers for sum calculation"
      correct_approach: "Use 64-bit integers or language with arbitrary precision"

    - title: Off-by-One Errors in Gap Calculation
      description: |
        When calculating the number of integers between `prev` and `num`, it's easy to make off-by-one mistakes.

        The count of integers from `a` to `b` inclusive is `b - a + 1`. The gap between `prev` (exclusive) and `num` (exclusive) contains `num - prev - 1` integers.

        Example: between `prev = 2` and `num = 5`, the available integers are `3, 4` — that's `5 - 2 - 1 = 2` integers.
      wrong_approach: "Miscounting gap size"
      correct_approach: "Gap from prev to num (exclusive both) is num - prev - 1"

  key_takeaways:
    - "**Arithmetic series formula**: Sum from 1 to n is `n * (n + 1) / 2`. This transforms O(n) iteration into O(1) calculation"
    - "**Gap-filling strategy**: When filling positions with constraints, sort the constraints and process gaps between them"
    - "**Greedy correctness**: Taking the smallest available integers first always yields the minimum sum — no need to consider alternatives"
    - "**Handle large ranges**: When k or values can be very large, look for mathematical formulas to avoid iteration"

  time_complexity: "O(n log n). Sorting dominates the complexity; processing the sorted array is O(n)."
  space_complexity: "O(n). We store the deduplicated sorted array. Can be O(1) extra space if we sort in-place and handle duplicates during iteration."

solutions:
  - approach_name: Greedy with Arithmetic Series
    is_optimal: true
    code: |
      def min_sum(nums: list[int], k: int) -> int:
          # Sort and deduplicate to process gaps in order
          nums = sorted(set(nums))
          result = 0
          prev = 0  # Last integer we've accounted for (start before 1)

          for num in nums:
              # How many integers are available between prev and num?
              gap = num - prev - 1

              if gap > 0:
                  # Take at most k integers from this gap
                  take = min(gap, k)
                  # Sum of integers from (prev + 1) to (prev + take)
                  # Using formula: sum = take * (first + last) / 2
                  first = prev + 1
                  last = prev + take
                  result += take * (first + last) // 2
                  k -= take

                  if k == 0:
                      return result

              prev = num

          # Still need more integers after the last element in nums
          if k > 0:
              first = prev + 1
              last = prev + k
              result += k * (first + last) // 2

          return result
    explanation: |
      **Time Complexity:** O(n log n) — Sorting the array dominates; iteration is O(n).

      **Space Complexity:** O(n) — Creating a sorted set of unique elements.

      We process gaps between consecutive elements in the sorted array, using the arithmetic series formula to efficiently sum ranges of consecutive integers. This avoids iterating through potentially billions of integers.

  - approach_name: Brute Force (TLE)
    is_optimal: false
    code: |
      def min_sum(nums: list[int], k: int) -> int:
          # Convert to set for O(1) lookup
          num_set = set(nums)
          result = 0
          current = 1

          # Find k integers not in nums
          while k > 0:
              if current not in num_set:
                  result += current
                  k -= 1
              current += 1

          return result
    explanation: |
      **Time Complexity:** O(k + n) — We iterate up to k + max(nums) times in the worst case.

      **Space Complexity:** O(n) — Storing nums in a set.

      This straightforward approach iterates through positive integers one by one, adding those not in nums. While correct, it's far too slow when k is large (up to 10^8). Included to illustrate why the arithmetic series approach is necessary.
