Design a Stack With Increment Operation

Updated on 22 May, 2025
Design a Stack With Increment Operation header image

Problem Statement

In this problem, you are required to design a special kind of stack called CustomStack that not only performs the usual push and pop operations but can also increment a specified number of elements starting from the bottom of the stack. The CustomStack allows for the initialization with a maximum size, providing a limit to the number of elements it can hold. Elements are added to the top unless the stack has reached its maximum capacity. The pop operation will remove the top element and return its value or return -1 if the stack is empty. Additionally, the increment operation is required to increase the value of the bottom k elements by a given value val. If the stack contains fewer than k elements, then all elements will be incremented.

Examples

Example 1

Input:

["CustomStack","push","push","pop","push","push","push","increment","increment","pop","pop","pop","pop"]
[[3],[1],[2],[],[2],[3],[4],[5,100],[2,100],[],[],[],[]]

Output:

[null,null,null,2,null,null,null,null,null,103,202,201,-1]

Explanation:

CustomStack stk = new CustomStack(3); // Stack is Empty []
stk.push(1); // stack becomes [1]
stk.push(2); // stack becomes [1, 2]
stk.pop(); // return 2 --> Return top of the stack 2, stack becomes [1]
stk.push(2); // stack becomes [1, 2]
stk.push(3); // stack becomes [1, 2, 3]
stk.push(4); // stack still [1, 2, 3], Do not add another elements as size is 4
stk.increment(5, 100); // stack becomes [101, 102, 103]
stk.increment(2, 100); // stack becomes [201, 202, 103]
stk.pop(); // return 103 --> Return top of the stack 103, stack becomes [201, 202]
stk.pop(); // return 202 --> Return top of the stack 202, stack becomes [201]
stk.pop(); // return 201 --> Return top of the stack 201, stack becomes []
stk.pop(); // return -1 --> Stack is empty return -1.

Constraints

  • 1 <= maxSize, x, k <= 1000
  • 0 <= val <= 100
  • At most 1000 calls will be made to each method of increment, push and pop each separately.

Approach and Intuition

The problem requires a stack with enhanced functionality. Here's a step-by-step breakdown of how the operations are handled:

  1. Initialization:

    • The CustomStack is initialized with a maximum size, maxSize. This size prevents more than maxSize elements from being added to the stack.
  2. Push Operation:

    • Before adding a new element to the stack with the push operation, check if the current size of the stack is less than maxSize.
    • If true, add the element to the top of the stack.
  3. Pop Operation:

    • Check if the stack is not empty before popping.
    • If the stack is empty, return -1.
    • If not, remove the top element from the stack and return its value.
  4. Increment Operation:

    • This operation adds more complexity. It requires incrementing the bottom k elements of the stack by a value val.
    • If k is greater than the current size of the stack, then all elements in the stack should be incremented.
    • Otherwise, only the bottom k elements are incremented.

By understanding these operations, we can maintain the stacking order and ensure the additional increment functionality does not disrupt the primary operations of push and pop. The design ensures efficiency and simplicity, keeping track of current size and applying increments directly to elements in the stack without additional structures. This approach also considers performance constraints, ensuring that each operation can handle up to 1000 calls efficiently.

Solutions

  • C++
  • Java
  • Python
cpp
class EnhancedStack {
private:
    vector<int> dataStack;
    vector<int> lazyIncrement;
    int stackTop;

public:
    EnhancedStack(int maxSize) {
        dataStack.resize(maxSize);
        lazyIncrement.resize(maxSize);
        stackTop = -1;
    }

    void push(int x) {
        if (stackTop < (int)(dataStack.size()) - 1) {
            dataStack[++stackTop] = x;
        }
    }

    int pop() {
        if (stackTop == -1) {
            return -1;
        }

        int value = dataStack[stackTop] + lazyIncrement[stackTop];

        if (stackTop > 0) {
            lazyIncrement[stackTop - 1] += lazyIncrement[stackTop];
        }

        lazyIncrement[stackTop] = 0;
        stackTop--;
        return value;
    }

    void addIncrement(int k, int val) {
        if (stackTop >= 0) {
            int limit = min(stackTop, k - 1);
            lazyIncrement[limit] += val;
        }
    }
};

For the given problem title "Design a Stack With Increment Operation", the C++ code implements an enhanced stack capable of not only standard push and pop operations but also a custom "increment" operation to efficiently increase the bottommost elements of the stack.

  • Initialization:

    • The EnhancedStack class is initialized with a specified maxSize. It uses two vectors: dataStack to store stack elements and lazyIncrement to manage increments for each position.
    • stackTop keeps track of the current top index of the stack, starting from -1 indicating the stack is empty.
  • Push Operation:

    • The push method checks if there is room to add an element (i.e., stackTop is less than the maximal index of dataStack). If so, increments stackTop and assigns the new item to that position.
  • Pop Operation:

    • The pop method first checks if the stack is empty. If not, it computes the value at stackTop by combining the base stack value and the increment stored at the same index.
    • Before decrementing stackTop, it propagates the increment value to the next element in the stack (if present). This lazy propagation ensures that only necessary computations occur, thereby enhancing efficiency.
    • Resets the increment at stackTop and returns the calculated value.
  • Increment Operation:

    • The addIncrement method increases elements from the base of the stack up to a given count (k). It uses the lazyIncrement vector for efficient range updating by adjusting the increment at the minimal index between stackTop and k-1.

This intelligently designed class efficiently manages increments to collections of elements at the stack's bottom with minimal computations, making the stack operations highly optimized for scenarios where frequent increment adjustments are needed alongside regular pushes and pops.

java
class EnhancedStack {
    private int[] elements;
    private int[] increments;
    private int stackTop;

    public EnhancedStack(int maxSize) {
        elements = new int[maxSize];
        increments = new int[maxSize];
        stackTop = -1;
    }

    public void push(int value) {
        if (stackTop < elements.length - 1) {
            elements[++stackTop] = value;
        }
    }

    public int pop() {
        if (stackTop < 0) {
            return -1;
        }
        
        int poppedValue = elements[stackTop] + increments[stackTop];

        if (stackTop > 0) {
            increments[stackTop - 1] += increments[stackTop];
        }

        increments[stackTop] = 0;
        stackTop--;
        return poppedValue;
    }

    public void increment(int k, int value) {
        if (stackTop >= 0) {
            int maxIncrementIndex = Math.min(stackTop, k - 1);
            increments[maxIncrementIndex] += value;
        }
    }
}

The given Java code defines an EnhancedStack class designed to implement a stack with an additional increment operation. This feature-rich stack allows standard functionality like push and pop operations, along with the ability to increment the bottom k elements of the stack by a specified value in a single operation.

Functionality Breakdown:

  • Initialization:

    • The EnhancedStack is initialized with a maxSize that determines the capacity of the stack.
    • Two arrays, elements and increments, are used where elements stores the actual stack elements and increments aids in the increment operation.
    • stackTop is an index tracking the top element of the stack.
  • Push Operation:

    • Adds a new element to the top of the stack if there's available space.
    • Increases the stackTop index accordingly.
  • Pop Operation:

    • Returns and removes the top element of the stack.
    • Applies any accrued increments to the popped element.
    • Propagates this increment to the next element if the stack isn't empty after the pop, ensuring any subsequent pops consider earlier increments.
  • Increment Operation:

    • Efficiently increases the bottom k elements' value by the given increment without iterating over the elements.
    • The increments array tracks increments at relevant positions, utilizing the propagation method during pops to apply these increments.

This implementation ensures all operations (push, pop, and increment) are efficiently handled, making it suitable for scenarios requiring swift stack manipulations with additional complex operations like the bottom element increments. The use of an increments array for deferred increment application optimizes the increment operation, especially for large stacks.

python
class StackContainer:
    def __init__(self, limit: int):
        self._elements = [0] * limit
        self._increments = [0] * limit
        self._currentIndex = -1

    def push(self, value: int) -> None:
        if self._currentIndex < len(self._elements) - 1:
            self._currentIndex += 1
            self._elements[self._currentIndex] = value

    def pop(self) -> int:
        if self._currentIndex == -1:
            return -1

        top_value = self._elements[self._currentIndex] + self._increments[self._currentIndex]
        
        if self._currentIndex != 0:
            self._increments[self._currentIndex - 1] += self._increments[self._currentIndex]
        self._increments[self._currentIndex] = 0
        self._currentIndex -= 1
        return top_value

    def increment(self, count: int, increment_value: int) -> None:
        if self._currentIndex >= 0:
            position = min(self._currentIndex, count - 1)
            self._increments[position] += increment_value

This Python solution describes the implementation of a custom stack class StackContainer with the capability to support normal stack operations and an additional increment operation. The class manages stack operations with the following methods:

  • __init__(self, limit: int):

    • Initializes the stack with two arrays, _elements for stack values and _increments for holding increments applicable to elements, based on a specified size limit.
    • A _currentIndex pointer is used to track the top element of the stack.
  • push(self, value: int) -> None:

    • Adds a new element value to the top of the stack if there is space (i.e., _currentIndex is less than the top boundary of the stack).
  • pop(self) -> int:

    • Removes the top element from the stack and returns its value, including any increments.
    • Adjusts the increment values so that the next top element, if available, receives the accumulated increments from the popped element.
  • increment(self, count: int, increment_value: int) -> None:

    • Applies an increment_value to the bottom count elements of the stack. If count exceeds the number of elements in the stack, the increment is applied up to the last element.

This implementation efficiently handles the increment operation in a way that does not require iterating over all elements every time an increment is applied; instead, it strategically updates increment values, adding computational efficiency in scenarios where there are frequent increment operations.

Comments

No comments yet.