Skip to content

First Negative in Every Window of Size K ​

GeeksforGeeks | Difficulty: Medium | Pattern: Queue / Deque


Problem Statement ​

Given an array arr[] of size N and a positive integer k, find the first negative integer for each and every window (contiguous subarray) of size k.

If a window does not contain a negative integer, output 0 for that window.

Examples ​

Example 1:

Input: arr = [12, -1, -7, 8, -15, 30, 16, 28], k = 3
Output: [-1, -1, -7, -15, -15, 0]

Window [12, -1, -7]:    First negative = -1
Window [-1, -7, 8]:     First negative = -1
Window [-7, 8, -15]:    First negative = -7
Window [8, -15, 30]:    First negative = -15
Window [-15, 30, 16]:   First negative = -15
Window [30, 16, 28]:    No negative, output 0

Example 2:

Input: arr = [1, 2, 3, 4, 5], k = 2
Output: [0, 0, 0, 0]

No negative numbers, all windows output 0

Constraints ​

  • 1 <= N <= 10^5
  • 1 <= k <= N
  • -10^5 <= arr[i] <= 10^5

Intuition ​

We need to track negative numbers in each window. A deque (double-ended queue) is perfect for this:

  • Add new negative indices to the back
  • Remove indices that fall outside the window from the front
  • The front of the deque is always the first negative in the current window

Key Insight: Only store indices of negative numbers. If deque is empty for a window, output 0.


Visualization ​

First Negative in Window

For arr = [12, -1, -7, 8, -15, 30, 16, 28], k = 3:

Window [12, -1, -7] (indices 0-2):
  Deque: [1, 2]  (indices of -1, -7)
  First negative at index 1: -1

Window [-1, -7, 8] (indices 1-3):
  Deque: [1, 2]
  First negative at index 1: -1

Window [-7, 8, -15] (indices 2-4):
  Index 1 out of window, popleft
  Deque: [2, 4]
  First negative at index 2: -7

Window [8, -15, 30] (indices 3-5):
  Index 2 out of window, popleft
  Deque: [4]
  First negative at index 4: -15

Window [-15, 30, 16] (indices 4-6):
  Deque: [4]
  First negative at index 4: -15

Window [30, 16, 28] (indices 5-7):
  Index 4 out of window, popleft
  Deque: []
  No negative, output 0

Solution ​

python
from collections import deque

def firstNegative(arr: list[int], k: int) -> list[int]:
    """
    Find first negative integer in each window of size k.

    Uses deque to track indices of negative numbers.

    Time: O(n) - each element added/removed at most once
    Space: O(k) - deque stores at most k indices
    """
    n = len(arr)
    result = []
    dq = deque()  # Stores indices of negative numbers

    # Process first window
    for i in range(k):
        if arr[i] < 0:
            dq.append(i)

    # First window result
    result.append(arr[dq[0]] if dq else 0)

    # Process remaining windows
    for i in range(k, n):
        # Remove index outside window
        while dq and dq[0] <= i - k:
            dq.popleft()

        # Add current index if negative
        if arr[i] < 0:
            dq.append(i)

        # Append first negative (or 0)
        result.append(arr[dq[0]] if dq else 0)

    return result
java
public long[] firstNegative(long[] arr, int k) {
    int n = arr.length;
    long[] result = new long[n - k + 1];
    Deque<Integer> dq = new ArrayDeque<>(); // indices of negative numbers

    for (int i = 0; i < k; i++) {
        if (arr[i] < 0) dq.offer(i);
    }
    result[0] = dq.isEmpty() ? 0 : arr[dq.peek()];

    for (int i = k; i < n; i++) {
        while (!dq.isEmpty() && dq.peek() <= i - k) dq.poll();
        if (arr[i] < 0) dq.offer(i);
        result[i - k + 1] = dq.isEmpty() ? 0 : arr[dq.peek()];
    }

    return result;
}

Complexity: Time O(n) · Space O(k)

  • Time: Each element added to deque at most once and removed at most once; total operations = 2n = O(n)
  • Space: Deque stores only indices of negative numbers within current window, at most k indices

Alternative: Simplified Version ​

python
from collections import deque

def firstNegative(arr: list[int], k: int) -> list[int]:
    """
    Simplified version with unified loop.
    """
    n = len(arr)
    result = []
    dq = deque()

    for i in range(n):
        # Add current if negative
        if arr[i] < 0:
            dq.append(i)

        # Process window once we have k elements
        if i >= k - 1:
            # Remove elements outside window
            while dq and dq[0] < i - k + 1:
                dq.popleft()

            # First negative or 0
            result.append(arr[dq[0]] if dq else 0)

    return result

Complexity: Time O(n) · Space O(k)

  • Time: Unified loop processes each element once; same O(n) amortized as two-phase version
  • Space: Deque bounded by window size k; stores at most k negative indices

Step-by-Step Walkthrough ​

For arr = [12, -1, -7, 8, -15, 30], k = 3:

Initial: dq = [], result = []

i=0, arr[0]=12:
  12 >= 0, don't add to dq
  i < k-1, no result yet

i=1, arr[1]=-1:
  -1 < 0, add 1 to dq
  dq = [1]
  i < k-1, no result yet

i=2, arr[2]=-7:
  -7 < 0, add 2 to dq
  dq = [1, 2]
  i >= k-1, window ready
  First negative at index 1: -1
  result = [-1]

i=3, arr[3]=8:
  8 >= 0, don't add
  dq = [1, 2]
  Check window [1, 3]: index 1 in window
  First negative at index 1: -1
  result = [-1, -1]

i=4, arr[4]=-15:
  -15 < 0, add 4 to dq
  dq = [1, 2, 4]
  Check window [2, 4]:
    - index 1 < 2, popleft -> dq = [2, 4]
  First negative at index 2: -7
  result = [-1, -1, -7]

i=5, arr[5]=30:
  30 >= 0, don't add
  dq = [2, 4]
  Check window [3, 5]:
    - index 2 < 3, popleft -> dq = [4]
  First negative at index 4: -15
  result = [-1, -1, -7, -15]

Final result = [-1, -1, -7, -15]

Complexity Analysis ​

AspectComplexityExplanation
TimeO(n)Each element added/removed at most once
SpaceO(k)Deque holds at most k elements

Edge Cases ​

python
def test_first_negative():
    # All positive
    assert firstNegative([1, 2, 3, 4], 2) == [0, 0, 0]

    # All negative
    assert firstNegative([-1, -2, -3, -4], 2) == [-1, -2, -3]

    # Single element windows
    assert firstNegative([1, -2, 3, -4], 1) == [0, -2, 0, -4]

    # Window size equals array length
    assert firstNegative([1, 2, -3, 4], 4) == [-3]

    # Negative at start
    assert firstNegative([-1, 2, 3, 4, 5], 3) == [-1, 0, 0]

    # Negative at end
    assert firstNegative([1, 2, 3, 4, -5], 3) == [0, 0, -5]

Variations ​

1. Last Negative in Every Window ​

python
def lastNegative(arr: list[int], k: int) -> list[int]:
    """Last negative in each window."""
    n = len(arr)
    result = []
    dq = deque()

    for i in range(n):
        if arr[i] < 0:
            dq.append(i)

        if i >= k - 1:
            while dq and dq[0] < i - k + 1:
                dq.popleft()

            # Return last in deque (not first)
            result.append(arr[dq[-1]] if dq else 0)

    return result

Complexity: Time O(n) · Space O(k)

  • Time: Same O(n) pattern; accessing dq[-1] instead of dq[0] is still O(1)
  • Space: Deque stores same indices; accessing from back does not change space usage

2. Count of Negatives in Every Window ​

python
def countNegatives(arr: list[int], k: int) -> list[int]:
    """Count negatives in each window."""
    n = len(arr)
    result = []
    count = 0

    # Count in first window
    for i in range(k):
        if arr[i] < 0:
            count += 1
    result.append(count)

    # Slide window
    for i in range(k, n):
        # Add new element
        if arr[i] < 0:
            count += 1
        # Remove old element
        if arr[i - k] < 0:
            count -= 1
        result.append(count)

    return result

Complexity: Time O(n) · Space O(1)

  • Time: Single pass with O(1) operations per element (increment/decrement count)
  • Space: Only maintains count variable and result array; no deque needed for counting

3. First Positive in Every Window ​

python
def firstPositive(arr: list[int], k: int) -> list[int]:
    """First positive in each window."""
    n = len(arr)
    result = []
    dq = deque()

    for i in range(n):
        if arr[i] > 0:  # Changed condition
            dq.append(i)

        if i >= k - 1:
            while dq and dq[0] < i - k + 1:
                dq.popleft()
            result.append(arr[dq[0]] if dq else 0)

    return result

Complexity: Time O(n) · Space O(k)

  • Time: Identical to first negative; only condition (arr[i] > 0) changes, not algorithm structure
  • Space: Deque stores positive indices instead of negative; same k-bounded space

Comparison with Sliding Window Maximum ​

AspectFirst NegativeSliding Window Maximum
Store in DequeIndices of negatives onlyAll indices (decreasing order)
Deque OrderAny order (just track presence)Monotonic decreasing
Remove from BackNoYes (smaller elements)
Empty Deque Result0N/A (always has max)

Interview Tips ​

What Interviewers Look For ​

  1. Deque Usage: Know when deque is appropriate
  2. Window Tracking: Properly slide the window
  3. Edge Cases: All positive, all negative, single element

Common Follow-up Questions ​

  1. "What if we need all negatives in the window?"

    • Return the deque contents for each window
  2. "How would you handle streaming data?"

    python
    class NegativeTracker:
        def __init__(self, k):
            self.k = k
            self.window = deque()
            self.negatives = deque()
            self.current_start = 0
    
        def add(self, num):
            self.window.append(num)
            if num < 0:
                self.negatives.append(len(self.window) - 1)
    
            if len(self.window) > self.k:
                if self.negatives and self.negatives[0] == self.current_start:
                    self.negatives.popleft()
                self.window.popleft()
                self.current_start += 1
    
        def getFirstNegative(self):
            if len(self.window) < self.k:
                return None
            return self.window[self.negatives[0] - self.current_start] if self.negatives else 0
  3. "What about finding the first number divisible by x?"

    • Same pattern, change the condition

Sliding Window Maximum (LeetCode 239)

Problem: Return maximum element in each sliding window of size k.

Key Insight: Monotonic decreasing deque. Front is always max. Remove smaller elements on insert.

Approach: Deque stores indices. Popleft if outside window. Pop smaller elements before push.

Complexity: O(n) time, O(k) space

First Unique Character in Stream

Problem: Return first non-repeating character in stream at each point.

Key Insight: Queue of candidates + hashmap of counts. Dequeue from front until unique found.

Approach: Queue stores order, hashmap tracks counts. Pop from front while count > 1.

Complexity: O(1) amortized per character

Moving Average from Data Stream (LeetCode 346)

Problem: Calculate moving average of last k elements in stream.

Key Insight: Simpler than first negative - just track sum and queue of k elements.

Approach: Queue maintains window. Track running sum. Average = sum / min(count, k).

Complexity: O(1) per call

Maximum of Minimum for Every Window Size

Problem: For each window size 1 to n, find maximum of all window minimums.

Key Insight: For each element, find window sizes where it's the minimum (using prev/next smaller).

Approach: Find left/right boundaries (smaller elements). Fill result array for those window sizes.

Complexity: O(n) time, O(n) space


References ​