From 87296e01b8671ac75b2ab3d653f3f92bf5eb474b Mon Sep 17 00:00:00 2001 From: Alex Small Date: Wed, 25 Mar 2026 13:53:57 +0000 Subject: [PATCH] Add best time to buy and sell stock solution and test files --- .../best-time-to-buy-and-sell-stock/.test.ts | 81 +++++++++++++++++++ .../solution.ts | 46 +++++++++++ 2 files changed, 127 insertions(+) create mode 100644 problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/.test.ts create mode 100644 problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/solution.ts diff --git a/problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/.test.ts b/problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/.test.ts new file mode 100644 index 0000000..dfea59e --- /dev/null +++ b/problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/.test.ts @@ -0,0 +1,81 @@ +import { test, expect, describe } from 'vitest' +import { nestedLoops, runningMin } from './solution' + +const expectCorrectProfit = (inputs: [number[], number][]) => { + inputs.forEach(([prices, expected]) => { + expect(nestedLoops(prices)).toBe(expected) + expect(runningMin(prices)).toBe(expected) + }) +} + +describe('Positive profit is returned correctly by both solutions when:', () => { + test('Best day to buy is minimum price and best day to sell is maximum price.', () => { + const inputs = [ + [[7,1,5,3,6,4], 5], + [[1,2,3,4,5], 4], + [[5,4,7,10, 11], 7], + [[8,4,5,6,20], 16] + ] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) + test('Maximum price is at the beginning of the array.', () => { + const inputs = [ + [[8,1,2,4], 3], + [[10,1,2,3], 2], + [[20, 1, 2, 19], 18], + [[100, 1, 2, 99], 98] + ] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) + test('Minimum price is at the end of the array.', () => { + const inputs = [ + [[3,4,6,8, 1], 5], + [[7,8,9,2], 2], + [[10, 11, 12, 1], 2], + [[50, 51, 52, 1], 2] + ] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) + test('Best day to buy is not minimum price.', () => { + const inputs = [ + [[2,7,1,4], 5], + [[3,10,2,3], 7], + [[3,20,1,17], 17], + ] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) +}) + +describe('Both solutions return zero profit correctly when:', () => { + test('Prices are in descending order.', () => { + const inputs = [ + [[7,6,4,3,1], 0], + [[9,7,4,2,1], 0], + [[50, 3, 2, 2, 1], 0], + [[100, 99, 97, 97, 97], 0] + ] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) + test('All prices are the same.', () => { + const inputs = [ + [[1,1,1,1], 0], + [[5,5,5,5], 0], + [[100, 100, 100, 100], 0], + [[999, 999, 999, 999], 0] + ] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) + test('Only one price is given.', () => { + const inputs = [[[1], 0], [[5], 0], [[100], 0], [[999], 0]] satisfies [number[], number][] + expectCorrectProfit(inputs) + }) +}) + +describe('Optimized solution runs for large inputs.', () => { + test('Input of 10^5 prices runs within time limit.', () => { + // Set array length to maximum allowed by problem constraints + const n = 10 ** 5 + const prices = Array.from({ length: n }, (_, i) => i + 1) + expect(runningMin(prices)).toBe(n - 1) + }) +}) \ No newline at end of file diff --git a/problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/solution.ts b/problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/solution.ts new file mode 100644 index 0000000..80e1aa0 --- /dev/null +++ b/problems/two-pointers-and-sliding-window/best-time-to-buy-and-sell-stock/solution.ts @@ -0,0 +1,46 @@ +// Solution 1: Brute force nested loops +// Time O(n^2), Space O(1) +// Solution 2: Running minimum +// Time O(n), Space O(1) + +/** + * Brute force nested loops + * Time O(n^2), Space O(1) + */ +export function nestedLoops(prices: number[]): number { + let max = 0 + + const n = prices.length + + for (let i=0; i max){ + max = profit + } + } + } + + return max +}; + +/** + * Running minimum + * Time O(n), Space O(1) + */ +export function runningMin(prices: number[]): number { + if (prices.length === 0) return 0 + + let minPrice = prices[0] + let bestProfit = 0 + let bestProfitToday = 0 + + prices.forEach((price) => { + bestProfitToday = price - minPrice + minPrice = Math.min(price, minPrice) + bestProfit = Math.max(bestProfit, bestProfitToday) + }) + + return bestProfit + +}; \ No newline at end of file