Optimal Investment Portfolio — Problem Statement & Solution Guide
Problem Description
You are provided with two arrays of equal length, prices and growthRates. The array prices contains the current market price of a set of distinct assets, while growthRates contains the expected annual percentage growth rate for each corresponding asset. Your objective is to identify the single asset that maximizes the absolute profit after one year. The profit for an asset is calculated as the product of its current price and its growth rate (expressed as a decimal). If multiple assets yield the same maximum profit, return the index of the asset with the lowest index. If all assets result in a non-positive profit, return -1 to indicate that no investment should be made.
The function should accept the two arrays as input and return an integer representing the index of the optimal asset. This problem simulates a simplified portfolio selection scenario where capital allocation is not a constraint, and the sole metric for optimization is the immediate absolute return on investment.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Optimal Investment Portfolio"
WHY DOES IT MATTER?
This pattern tests the ability to recognize when a problem is simpler than it appears. Many candidates over-engineer solutions by introducing sorting or hash maps for problems that only require a linear scan. Recognizing that the objective function is separable (each element's contribution is independent) is a key skill in algorithmic design.
OPTIMIZATION CHALLENGE
The key insight is that no preprocessing (like sorting) is needed. The optimal solution is a single pass through the arrays. The challenge is not algorithmic complexity but rather handling edge cases like zero prices, negative growth, and floating-point precision. The 'optimization' is avoiding unnecessary O(N log N) sorting steps that do not contribute to finding the maximum.
REAL-WORLD CONNECTION
This is analogous to a real-time stock ticker system where the engine must identify the top-performing stock in a stream of updates. The system cannot wait for all data to be loaded; it must process each tick in O(1) time and update the 'top performer' state incrementally. This is a classic map-reduce pattern where the 'map' is the profit calculation and the 'reduce' is the max operation.
In an interview, explicitly state that you are performing a single linear scan. Mention that you are tracking the maximum value seen so far. If the interviewer asks about scalability, pivot to the streaming/O(1) space argument. Avoid writing code that stores intermediate profits in a new array; compute and compare on the fly to demonstrate space efficiency.
COMPLEXITY AT A GLANCE
O(N)O(1)Core Theory — Why This Approach?
The problem of identifying the asset with maximum absolute profit after one year is fundamentally a linear scan problem involving element-wise arithmetic operations. Given two arrays, prices and growthRates, the profit for the i-th asset is defined as prices[i] * (growthRates[i] / 100.0). The objective is to find the index i that maximizes this value. While the problem statement suggests a complex optimization, the mathematical definition of 'absolute profit' in this specific context (single period, fixed growth rate) simplifies to a direct comparison of computed values. There is no need for sorting, dynamic programming, or advanced data structures because the profit of each asset is independent of the others. The dependency is strictly local to the pair (prices[i], growthRates[i]).
Interview Questions on This Problem
Q1In a fintech platform, if we have 10 million assets, how would you optimize the memory footprint when calculating the maximum profit if the arrays are streamed from a database?
Since the calculation for each asset is independent, you can process the data in a single pass without storing the entire arrays in memory. You would iterate through the stream, compute the profit for each record on the fly, and maintain a single variable maxProfit to track the highest value seen so far. This reduces space complexity from O(N) to O(1) and prevents memory overflow issues associated with loading large datasets into RAM.
Q2What if the growth rates can be negative? How does that change the logic for finding the 'maximum absolute profit'?
If growth rates can be negative, the 'profit' can be negative (a loss). The term 'absolute profit' might be ambiguous. If it means the largest gain, you still maximize the signed value. If it means the largest magnitude of change (gain or loss), you would maximize abs(prices[i] * growthRates[i] / 100.0). In a standard investment context, 'maximizing profit' implies maximizing the signed value (highest gain). However, if the question explicitly asks for 'absolute profit' to include losses as a metric of volatility, you must take the absolute value before comparison. Clarifying the definition of 'profit' is crucial in interviews.
Q3How would you handle floating-point precision errors when comparing profits calculated from large price values and small growth rates?
Floating-point arithmetic can introduce rounding errors. Instead of using strict equality or direct comparison that might fail due to epsilon differences, you should use a tolerance-based comparison or, better yet, avoid division by 100 until the final comparison if possible. However, since we are maximizing, the relative order is usually preserved. To be safe, you can compare profit1 > profit2 + epsilon where epsilon is a small value like 1e-9. Alternatively, if the inputs are integers, you can compare prices[i] * growthRates[i] directly, as dividing by a constant positive number (100) does not change the relative ordering of the products.
Examples
Input
prices = [100, 200, 150], growthRates = [0.10, 0.05, 0.20]
Output
2
Explanation: Calculate the profit for each asset: Asset 0 yields 100 * 0.10 = 10. Asset 1 yields 200 * 0.05 = 10. Asset 2 yields 150 * 0.20 = 30. The maximum profit is 30, which corresponds to the asset at index 2. Therefore, the function returns 2.
Input
prices = [50, 50, 50], growthRates = [0.15, 0.15, 0.10]
Output
0
Explanation: Calculate the profit for each asset: Asset 0 yields 50 * 0.15 = 7.5. Asset 1 yields 50 * 0.15 = 7.5. Asset 2 yields 50 * 0.10 = 5.0. The maximum profit is 7.5, which is achieved by both Asset 0 and Asset 1. According to the tie-breaking rule, we select the asset with the lowest index, which is 0.
Input
prices = [10, 20, 30], growthRates = [-0.05, -0.10, 0.00]
Output
-1
Explanation: Calculate the profit for each asset: Asset 0 yields 10 * -0.05 = -0.5. Asset 1 yields 20 * -0.10 = -2.0. Asset 2 yields 30 * 0.00 = 0.0. All calculated profits are non-positive (less than or equal to zero). Therefore, the function returns -1, indicating that no asset should be selected.
Input
prices = [1000, 500], growthRates = [0.01, 0.03]
Output
1
Explanation: Calculate the profit for each asset: Asset 0 yields 1000 * 0.01 = 10. Asset 1 yields 500 * 0.03 = 15. The maximum profit is 15, which corresponds to the asset at index 1. Therefore, the function returns 1.
Constraints
- 1 <= prices.length <= 10^5
- prices.length == growthRates.length
- 1 <= prices[i] <= 10^6
- -1.0 <= growthRates[i] <= 1.0
- growthRates[i] is a float with up to 2 decimal places
Optimal Approach & Strategy
Iterate through the input arrays once, calculating the profit for each asset on the fly. Keep track of the maximum profit and its corresponding index in variables, updating them whenever a higher profit is found.
Brute Force Approach
Calculate the profit for every asset and store them in a new array. Then, iterate through this new array to find the maximum value and its index.
Verified Code Solutions
/**
* @param {number[]} prices - Array of current asset prices.
* @param {number[]} growthRates - Array of expected annual growth rates.
* @return {number} The index of the asset with the maximum absolute profit.
*/
function optimalInvestmentPortfolio(prices, growthRates) {
if (prices.length === 0) {
return -1;
}
let maxProfit = -Infinity;
let maxIndex = 0;
for (let i = 0; i < prices.length; i++) {
const profit = prices[i] * growthRates[i];
if (profit > maxProfit) {
maxProfit = profit;
maxIndex = i;
}
}
return maxIndex;
}
// Example usage
const prices = [100, 200, 150];
const growthRates = [0.10, 0.05, 0.20];
console.log(optimalInvestmentPortfolio(prices, growthRates));#include <iostream>
#include <vector>
#include <cmath>
#include <limits>
using namespace std;
int optimalInvestmentPortfolio(vector<int>& prices, vector<double>& growthRates) {
if (prices.empty()) {
return -1;
}
double maxProfit = numeric_limits<double>::lowest();
int maxIndex = 0;
for (size_t i = 0; i < prices.size(); ++i) {
double profit = static_cast<double>(prices[i]) * growthRates[i];
if (profit > maxProfit) {
maxProfit = profit;
maxIndex = static_cast<int>(i);
}
}
return maxIndex;
}
int main() {
vector<int> prices = {100, 200, 150};
vector<double> growthRates = {0.10, 0.05, 0.20};
int result = optimalInvestmentPortfolio(prices, growthRates);
cout << result << endl;
return 0;
}import java.util.*;
public class Solution {
public static int optimalInvestmentPortfolio(int[] prices, double[] growthRates) {
if (prices == null || prices.length == 0) {
return -1;
}
double maxProfit = Double.NEGATIVE_INFINITY;
int maxIndex = 0;
for (int i = 0; i < prices.length; i++) {
double profit = prices[i] * growthRates[i];
if (profit > maxProfit) {
maxProfit = profit;
maxIndex = i;
}
}
return maxIndex;
}
public static void main(String[] args) {
int[] prices = {100, 200, 150};
double[] growthRates = {0.10, 0.05, 0.20};
int result = optimalInvestmentPortfolio(prices, growthRates);
System.out.println(result);
}
}def optimal_investment_portfolio(prices, growth_rates):
"""
Find the index of the asset with the maximum absolute profit after one year.
Args:
prices (list): List of current asset prices.
growth_rates (list): List of expected annual growth rates.
Returns:
int: The index of the asset with the maximum absolute profit.
"""
if not prices:
return -1
max_profit = float('-inf')
max_index = 0
for i in range(len(prices)):
profit = prices[i] * growth_rates[i]
if profit > max_profit:
max_profit = profit
max_index = i
return max_index
if __name__ == "__main__":
prices = [100, 200, 150]
growth_rates = [0.10, 0.05, 0.20]
print(optimal_investment_portfolio(prices, growth_rates))/**
* @param {number[]} prices - Array of current asset prices.
* @param {number[]} growthRates - Array of expected annual growth rates.
* @return {number} The index of the asset with the maximum absolute profit.
*/
function optimalInvestmentPortfolio(prices, growthRates) {
if (prices.length === 0) {
return -1;
}
let maxProfit = -Infinity;
let maxIndex = 0;
for (let i = 0; i < prices.length; i++) {
const profit = prices[i] * growthRates[i];
if (profit > maxProfit) {
maxProfit = profit;
maxIndex = i;
}
}
return maxIndex;
}
// Example usage
const prices = [100, 200, 150];
const growthRates = [0.10, 0.05, 0.20];
console.log(optimalInvestmentPortfolio(prices, growthRates));Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.