Talentd
FleetCode
Make and follow sheets.Sign in

Number of Smooth Descent Periods of a Stock solution and explanation

MediumArrayDynamic ProgrammingMath6 min read67.7% acceptanceUpdated 9 Apr 2026
Number of Smooth Descent Periods of a Stock | Simple Approach | Leetcode 2110 | codestorywithMIKcodestorywithMIK · 10:21 · 4K viewsWatch on YouTube
9 more videos on this problem
  1. Number of Smooth Descent Periods of a Stock | Simple Approach | Leetcode 2110 | codestorywithMIKcodestorywithMIK · 10:21 · 4K views
  2. Number of Smooth Descent Periods of a Stock | Leetcode 2110 | Live coding session | DP 🔥🔥🔥Coding Decoded · 7:40 · 991 views
  3. 2110. Number of Smooth Descent Periods of a Stock (Leetcode Medium)Programming Live with Larry · 4:48 · 569 views
  4. Number of Smooth Descent Periods of a Stock | LeetCode 2110 | No DP requiredSanyam IIT Guwahati · 8:19 · 464 views
  5. Daily Leetcode #2085: Dec 15, 2025 - 2110. Number of Smooth Descent Periods of a StockProgramming Live with Larry · 8:04 · 398 views
  6. 2110. Number of Smooth Descent Periods of a Stock | Leetcode Daily - PythonLeetcode Daily · 10:45 · 371 views
  7. Number of Smooth Descent Periods of a Stock | Leetcode 2110 | DSA | Hindi | Code With DeepakCode with Deepak · 6:42 · 208 views
  8. LeetCode | 2110. Number of Smooth Descent Periods of a Stock | Sliding WindowCompl3x · 14:41 · 187 views
  9. Number of Smooth Descent Periods of a Stock | LeetCode 2110 - Pythonimpoldev · 9:01 · 183 views
  10. Leetcode 2110. Number of Smooth Descent Periods of a StockElite Code · 14:07 · 135 views

The problem

You are given an integer array prices representing the daily price history of a stock, where prices[i] is the stock price on the ith day.

A smooth descent period of a stock consists of one or more contiguous days such that the price on each day is lower than the price on the preceding day by exactly 1. The first day of the period is exempted from this rule.

Return the number of smooth descent periods.

Example 1:

Input: prices = [3,2,1,4]
Output: 7
Explanation: There are 7 smooth descent periods:
[3], [2], [1], [4], [3,2], [2,1], and [3,2,1]
Note that a period with one day is a smooth descent period by the definition.

Example 2:

Input: prices = [8,6,7,7]
Output: 4
Explanation: There are 4 smooth descent periods: [8], [6], [7], and [7]
Note that [8,6] is not a smooth descent period as 8 - 6 ≠ 1.

Example 3:

Input: prices = [1]
Output: 1
Explanation: There is 1 smooth descent period: [1]

Constraints:

  • 1 <= prices.length <= 105
  • 1 <= prices[i] <= 105

Approach overview

Problem Overview: You receive an integer array prices representing the daily stock price. A smooth descent period is a contiguous subarray where each element is exactly 1 less than the previous element. Every single element also counts as a valid period. The goal is to count the total number of such periods across the entire array.

Approach 1: Using a Stack (O(n) time, O(n) space)

This approach tracks the current descent sequence using a stack. Iterate through the array and compare each price with the previous value. If prices[i] == prices[i-1] - 1, the descent continues, so push the value onto the stack and increase the running count by the current stack size. If the condition breaks, reset the stack because the descent sequence ends and a new one begins. The key insight: every extension of a valid descent sequence creates multiple new subarrays ending at the current index. The stack effectively stores the active decreasing run. This approach is intuitive when reasoning about contiguous patterns in array traversal and makes it easy to visualize how subarrays expand.

Approach 2: Recursive Evaluation (O(n) time, O(n) space)

The recursive method evaluates the length of the descent sequence starting at each index. If prices[i+1] == prices[i] - 1, the sequence extends and the recursion continues to the next index. Otherwise, the recursion terminates and returns 1 because a single element still forms a valid descent period. Memoization stores previously computed results to avoid recomputation, turning the recursion into a top‑down dynamic programming solution. Each recursive call calculates how many valid subarrays start at that position, and the final answer sums all results. The logic closely mirrors the mathematical definition of the descent rule and works well when modeling state transitions.

Both methods rely on the same observation: if a descending run has length k, it contributes k * (k + 1) / 2 valid subarrays. Recognizing this pattern simplifies counting and connects the solution to basic math reasoning about sequences.

Recommended for interviews: The linear scan approach implemented with stack-like tracking is what most interviewers expect. It processes the array once, maintains a running descent length, and accumulates counts in O(n) time. The recursive formulation shows deeper understanding of the state transition and can help explain the dynamic programming structure, but iterative O(n) traversal demonstrates stronger practical optimization skills.

Approach 1: Approach 1: Using a Stack

This approach uses a stack to efficiently manage and track data as we process it. Stacks are last-in, first-out (LIFO) data structures that allow us to handle nested or hierarchical data effectively, such as the problem of parsing or evaluating expressions.

def evaluate_expression(expression):
    stack = []
    for c in expression:
        if c.isdigit():
            stack.append(int(c))
        else:
            val1 = stack.pop()
            val2 = stack.pop()
            if c == '+':
                stack.append(val2 + val1)
            # Additional operations can be added similarly
    return stack.pop()

expression = "23+"
print("The result is:", evaluate_expression(expression))
import java.util.Stack;

public class Main {
    public static int evaluateExpression(String expression) {
        Stack<Integer> stack = new Stack<>();
        for (char c : expression.toCharArray()) {
            if (Character.isDigit(c)) {
                stack.push(c - '0');
            } else {
                int val1 = stack.pop();
                int val2 = stack.pop();
                if (c == '+') {
                    stack.push(val2 + val1);
                }
                // Additional operations can be added similarly
            }
        }
        return stack.pop();
    }

    public static void main(String[] args) {
        String expression = "23+";
        System.out.println("The result is: " + evaluateExpression(expression));
    }
}
#include <iostream>
#include <stack>
#include <string>
#include <cctype>

int evaluateExpression(const std::string &expression) {
    std::stack<int> stack;
    for (char c : expression) {
        if (isdigit(c)) {
            stack.push(c - '0');
        } else {
            int val1 = stack.top(); stack.pop();
            int val2 = stack.top(); stack.pop();
            if (c == '+') {
                stack.push(val2 + val1);
            }
            // Additional operations can be added similarly
        }
    }
    return stack.top();
}

int main() {
    std::string expression = "23+";
    std::cout << "The result is: " << evaluateExpression(expression) << std::endl;
    return 0;
}
function evaluateExpression(expression) {
    let stack = [];
    for (let i = 0; i < expression.length; i++) {
        let c = expression[i];
        if (!isNaN(c)) {
            stack.push(parseInt(c, 10));
        } else {
            let val1 = stack.pop();
            let val2 = stack.pop();
            if (c === '+') {
                stack.push(val2 + val1);
            }
            // Additional operations can be added similarly
        }
    }
    return stack.pop();
}

let expression = "23+";
console.log("The result is:", evaluateExpression(expression));
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100

typedef struct Stack {
    int top;
    int items[MAX];
} Stack;

void push(Stack* stack, int element) {
    if (stack->top == MAX - 1) {
        printf("Stack Overflow\n");
        return;
    }
    stack->items[++stack->top] = element;
}

int pop(Stack* stack) {
    if (stack->top == -1) {
        printf("Stack Underflow\n");
        return -1;
    }
    return stack->items[stack->top--];
}

int isEmpty(Stack* stack) {
    return stack->top == -1;
}

int evaluateExpression(const char* expression) {
    int i;
    Stack stack;
    stack.top = -1;
    for (i = 0; i < strlen(expression); i++) {
        if (isdigit(expression[i])) {
            push(&stack, expression[i] - '0');
        } else {
            if (expression[i] == '+') {
                int val1 = pop(&stack);
                int val2 = pop(&stack);
                push(&stack, val2 + val1);
            }
            // Additional operations can be added similarly
        }
    }
    return pop(&stack);
}

int main() {
    char expression[] = "23+";
    printf("The result is: %d\n", evaluateExpression(expression));
    return 0;
}
using System;
using System.Collections.Generic;

class MainClass {
    public static int EvaluateExpression(string expression) {
        Stack<int> stack = new Stack<int>();
        foreach (char c in expression) {
            if (Char.IsDigit(c)) {
                stack.Push(c - '0');
            } else {
                int val1 = stack.Pop();
                int val2 = stack.Pop();
                if (c == '+') {
                    stack.Push(val2 + val1);
                }
                // Additional operations can be added similarly
            }
        }
        return stack.Pop();
    }

    public static void Main(string[] args) {
        string expression = "23+";
        Console.WriteLine("The result is: " + EvaluateExpression(expression));
    }
}

This Python solution utilizes a list as a stack to process a postfix expression. It pushes operands onto the stack and applies operators to operands popped from the stack, continuing until the expression is fully evaluated.

Complexity

Time Complexity: O(n), Space Complexity: O(n), where n is the length of the expression.

Try this approach in the editor

Approach 2: Approach 2: Recursive Evaluation

This approach utilizes recursion to evaluate the expression. Recursive functions are a profound way to break down complex problems into simpler instances of the same problem. Here, recursion helps by breaking the expression into parts that can be independently processed.

def evaluate_recursive(expr, index):
    if index >= len(expr):
        return 0, index
    result = 0
    while index < len(expr):
        c = expr[index]
        if c.isdigit():
            result = int(c)
            index += 1
        else:
            index += 1
            operand1 = result
            operand2, index = evaluate_recursive(expr, index)
            if c == '+':
                result = operand1 + operand2
            # Additional operations can be added similarly
    return result, index

expression = "23+"
result, _ = evaluate_recursive(expression, 0)
print("The result is:", result)
public class Main {
    public static int evaluateRecursive(String expr, int[] index) {
        int result = 0;
        while (index[0] < expr.length()) {
            char c = expr.charAt(index[0]);
            if (Character.isDigit(c)) {
                result = c - '0';
                index[0]++;
            } else {
                index[0]++;
                int operand1 = result;
                int operand2 = evaluateRecursive(expr, index);
                if (c == '+') {
                    result = operand1 + operand2;
                }
                // Additional operations can be added similarly
            }
        }
        return result;
    }

    public static void main(String[] args) {
        String expression = "23+";
        int[] index = {0};
        System.out.println("The result is: " + evaluateRecursive(expression, index));
    }
}
#include <iostream>
#include <string>

int evaluateRecursive(const std::string &expr, int &index) {
    int result = 0;
    while (index < expr.length()) {
        char c = expr[index];
        if (isdigit(c)) {
            result = c - '0';
            index++;
        } else {
            index++;
            int operand1 = result;
            int operand2 = evaluateRecursive(expr, index);
            if (c == '+') {
                result = operand1 + operand2;
            }
            // Additional operations can be added similarly
        }
    }
    return result;
}

int main() {
    std::string expression = "23+";
    int index = 0;
    std::cout << "The result is: " << evaluateRecursive(expression, index) << std::endl;
    return 0;
}
function evaluateRecursive(expr, index) {
    let result = 0;
    while (index[0] < expr.length) {
        let c = expr[index[0]];
        if (!isNaN(c)) {
            result = parseInt(c, 10);
            index[0]++;
        } else {
            index[0]++;
            let operand1 = result;
            let operand2 = evaluateRecursive(expr, index);
            if (c === '+') {
                result = operand1 + operand2;
            }
            // Additional operations can be added similarly
        }
    }
    return result;
}

let expression = "23+";
let index = [0];
console.log("The result is:", evaluateRecursive(expression, index));
#include <stdio.h>
#include <ctype.h>

int evaluateRecursive(const char* expr, int* index) {
    int result = 0;
    while (expr[*index] != '\0') {
        char c = expr[*index];
        if (isdigit(c)) {
            result = c - '0';
            (*index)++;
        } else {
            (*index)++;
            int operand1 = result;
            int operand2 = evaluateRecursive(expr, index);
            if (c == '+') {
                result = operand1 + operand2;
            }
            // Additional operations can be added similarly
        }
    }
    return result;
}

int main() {
    const char* expression = "23+";
    int index = 0;
    printf("The result is: %d\n", evaluateRecursive(expression, &index));
    return 0;
}
using System;

class MainClass {
    public static int EvaluateRecursive(string expr, ref int index) {
        int result = 0;
        while (index < expr.Length) {
            char c = expr[index];
            if (Char.IsDigit(c)) {
                result = c - '0';
                index++;
            } else {
                index++;
                int operand1 = result;
                int operand2 = EvaluateRecursive(expr, ref index);
                if (c == '+') {
                    result = operand1 + operand2;
                }
                // Additional operations can be added similarly
            }
        }
        return result;
    }

    public static void Main(string[] args) {
        string expression = "23+";
        int index = 0;
        Console.WriteLine("The result is: " + EvaluateRecursive(expression, ref index));
    }
}

This Python solution applies recursion for evaluating a postfix expression. By processing each part of the expression through recursive calls, it provides a straightforward mechanism to handle the overall evaluation.

Complexity

Time Complexity: O(n), Space Complexity: O(n), based on the recursion depth which correlates with expression length.

Try this approach in the editor

Approach 3: Two Pointers

We define an answer variable ans with an initial value of 0.

Next, we use two pointers i and j, which point to the first day of the current smooth descent period and the day after the last day, respectively. Initially, i = 0 and j = 0.

We traverse the array prices from left to right. For each position i, we move j to the right until j reaches the end of the array or prices[j - 1] - prices[j] neq 1. At this point, cnt = j - i is the length of the current smooth descent period, and we add \frac{(1 + cnt) times cnt}{2} to the answer variable ans. Then we update i to j and continue traversing.

After the traversal ends, we return the answer variable ans.

The time complexity is O(n), where n is the length of the array prices. The space complexity is O(1).

function getDescentPeriods(prices: number[]): number {
    let ans = 0;
    const n = prices.length;
    for (let i = 0, j = 0; i < n; i = j) {
        j = i + 1;
        while (j < n && prices[j - 1] - prices[j] === 1) {
            ++j;
        }
        const cnt = j - i;
        ans += Math.floor(((1 + cnt) * cnt) / 2);
    }
    return ans;
}
func getDescentPeriods(prices []int) (ans int64) {
	n := len(prices)
	for i, j := 0, 0; i < n; i = j {
		j = i + 1
		for j < n && prices[j-1]-prices[j] == 1 {
			j++
		}
		cnt := j - i
		ans += int64((1 + cnt) * cnt / 2)
	}
	return
}
impl Solution {
    pub fn get_descent_periods(prices: Vec<i32>) -> i64 {
        let mut ans: i64 = 0;
        let n: usize = prices.len();
        let mut i: usize = 0;

        while i < n {
            let mut j: usize = i + 1;
            while j < n && prices[j - 1] - prices[j] == 1 {
                j += 1;
            }
            let cnt: i64 = (j - i) as i64;
            ans += (1 + cnt) * cnt / 2;
            i = j;
        }

        ans
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Approach 1: Using a Stack

Time Complexity: O(n), Space Complexity: O(n), where n is the length of the expression.

Approach 2: Recursive Evaluation

Time Complexity: O(n), Space Complexity: O(n), based on the recursion depth which correlates with expression length.

Two Pointers–

Complexity analysis

ApproachTimeSpaceWhen to Use
Stack-based Descent TrackingO(n)O(n)Best general solution for scanning arrays and counting valid descent segments efficiently
Recursive Evaluation with MemoizationO(n)O(n)Useful for demonstrating dynamic programming reasoning or recursive state transitions

Frequently asked questions

Is Number of Smooth Descent Periods of a Stock easy or hard?

The problem is classified as Medium because the brute-force approach is straightforward but inefficient. The challenge is recognizing that consecutive decreasing sequences can be counted incrementally. Once the streak-counting insight is identified, the final algorithm becomes a simple O(n) array traversal.

Number of Smooth Descent Periods of a Stock Python/Java solution

Python and Java implementations typically iterate once through the prices array while maintaining a variable for the current descent length. When prices[i] == prices[i-1] - 1, increase the streak; otherwise reset it to 1. Add the streak to the total count each step, producing an O(n) time solution.

How to solve Number of Smooth Descent Periods of a Stock in O(n)?

Traverse the array once while keeping a variable that stores the current descent length. If the difference between consecutive prices is exactly -1, increment the streak; otherwise reset it to 1. Add the streak length to the total at every step because each extension forms additional valid subarrays ending at that index.

What is the best approach for Number of Smooth Descent Periods of a Stock?

The best approach is a linear scan that tracks the current smooth descent length while iterating through the array. If prices[i] equals prices[i-1] - 1, extend the current streak and add its length to the total count. Otherwise reset the streak to 1. This runs in O(n) time and requires O(1) or O(n) auxiliary space depending on implementation.

Is Number of Smooth Descent Periods of a Stock asked at Google/Amazon/Meta?

Array pattern counting and sequence analysis problems like this frequently appear in interviews at companies such as Amazon, Google, and Meta. The question tests recognition of consecutive patterns and efficient subarray counting. Interviewers typically expect an O(n) traversal rather than brute force.

What data structure is used in Number of Smooth Descent Periods of a Stock?

The core structure is a simple array traversal. Some implementations use a stack to track the active descending sequence, while others maintain a running counter representing the current descent length. The recursive variant models the logic using dynamic programming with memoization.

What is the time complexity of Number of Smooth Descent Periods of a Stock?

The optimal solution runs in O(n) time because the algorithm processes each price exactly once while maintaining the current descent streak. Brute-force enumeration of all subarrays would take O(n^2), but the streak counting technique avoids rechecking elements. Space complexity is O(1) for iterative implementations or O(n) if recursion with memoization is used.

Comments

Now write it yourselfClose this page and solve Number of Smooth Descent Periods of a Stock in the editor, without looking.
Practise Number of Smooth Descent Periods of a Stock