Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Elementary Algorithms / Arrays and Dynamic Programming

1.2.3 Two Pointers

1-Elementary-Algorithms/1.2.3_Two_Pointers.cpp

View on GitHub

Uses two moving indices to process subarrays in linear time. This technique is most useful when expanding the right endpoint of a window monotonically and shrinking the left endpoint monotonically preserves enough state to test a condition or update an answer.

The examples below cover two common patterns: finding the shortest subarray with sum at least a target when all values are nonnegative, and finding the longest subarray with at most k distinct values.

  • min_length_at_least(a, target) returns the minimum length of a contiguous subarray with sum at least target, or $-1$ if none exists. Values in a must be nonnegative.
  • longest_at_most_k_distinct(a, k) returns the maximum length of a contiguous subarray containing at most k distinct values.

Implementation

#include <algorithm>
#include <cstdint>
#include <unordered_map>
#include <vector>

int min_length_at_least(const std::vector<int> &a, int64_t target) {
  int best = static_cast<int>(a.size()) + 1;
  int64_t sum = 0;
  for (int l = 0, r = 0; r < static_cast<int>(a.size()); r++) {
    sum += a[r];
    while (sum >= target) {
      best = std::min(best, r - l + 1);
      sum -= a[l++];
    }
  }
  return best == static_cast<int>(a.size()) + 1 ? -1 : best;
}

int longest_at_most_k_distinct(const std::vector<int> &a, int k) {
  if (k <= 0) {
    return 0;
  }
  std::unordered_map<int, int> count;
  int best = 0;
  for (int l = 0, r = 0; r < static_cast<int>(a.size()); r++) {
    count[a[r]]++;
    while (static_cast<int>(count.size()) > k) {
      if (--count[a[l]] == 0) {
        count.erase(a[l]);
      }
      l++;
    }
    best = std::max(best, r - l + 1);
  }
  return best;
}

Example Usage

#include <cassert>
using namespace std;

int main() {
  vector<int> a{2, 3, 1, 2, 4, 3};
  assert(min_length_at_least(a, 7) == 2);  // [4, 3].

  vector<int> b{1, 2, 1, 3, 4, 3, 5};
  assert(longest_at_most_k_distinct(b, 2) == 3);  // [1, 2, 1].
  return 0;
}