{x}
blog image

Number of Smooth Descent Periods of a Stock

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

Solution Explanation:

The problem asks to find the number of smooth descent periods in a given array of stock prices. A smooth descent period is defined as one or more contiguous days where the price on each day is exactly 1 lower than the price on the preceding day (except for the first day).

The most efficient approach to solve this problem is using a two-pointer technique. This avoids nested loops, resulting in a linear time complexity solution.

Algorithm:

  1. Initialization:

    • ans: A variable to store the total count of smooth descent periods, initialized to 0.
    • i: A pointer representing the start of a smooth descent period. Starts at index 0.
    • j: A pointer representing the end of a smooth descent period. Starts at index 0.
  2. Iteration:

    • The outer loop iterates through the prices array using pointer i.
    • The inner loop (using pointer j) finds the end of the current smooth descent period. It continues as long as j is within the array bounds and the difference between consecutive prices is exactly 1 (prices[j - 1] - prices[j] == 1).
    • cnt = j - i: Calculates the length of the current smooth descent period.
    • ans += (1 + cnt) * cnt // 2: Adds the number of smooth descent periods found within this segment to ans. The formula (1 + cnt) * cnt // 2 represents the sum of integers from 1 to cnt (representing the number of sub-periods within the current period). Integer division (//) is used to handle potential integer overflow in certain programming languages.
    • i = j: Moves i to the beginning of the next smooth descent period.
  3. Return Value:

    • The function returns the final value of ans, which is the total number of smooth descent periods.

Time Complexity: O(n) - The algorithm iterates through the prices array once. The inner loop only advances j until it finds the end of a smooth descent period, ensuring linear time complexity overall.

Space Complexity: O(1) - The algorithm uses a constant amount of extra space regardless of the input size.

Code in Different Languages:

The code implementations provided in the original response are already well-structured and efficient. I'll present them again here for clarity:

Python3:

class Solution:
    def getDescentPeriods(self, prices: List[int]) -> int:
        ans = 0
        i, n = 0, len(prices)
        while i < n:
            j = i + 1
            while j < n and prices[j - 1] - prices[j] == 1:
                j += 1
            cnt = j - i
            ans += (1 + cnt) * cnt // 2
            i = j
        return ans

Java:

class Solution {
    public long getDescentPeriods(int[] prices) {
        long ans = 0;
        int n = prices.length;
        for (int i = 0, j = 0; i < n; i = j) {
            j = i + 1;
            while (j < n && prices[j - 1] - prices[j] == 1) {
                ++j;
            }
            int cnt = j - i;
            ans += (1L + cnt) * cnt / 2;
        }
        return ans;
    }
}

C++:

class Solution {
public:
    long long getDescentPeriods(vector<int>& prices) {
        long long ans = 0;
        int n = prices.size();
        for (int i = 0, j = 0; i < n; i = j) {
            j = i + 1;
            while (j < n && prices[j - 1] - prices[j] == 1) {
                ++j;
            }
            int cnt = j - i;
            ans += (1LL + cnt) * cnt / 2;
        }
        return ans;
    }
};

Go:

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
}

TypeScript:

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;
}

These codes all implement the same algorithm with minor syntactic differences based on the language. They all achieve the optimal O(n) time complexity and O(1) space complexity.