Distribute a large value among a small number of elements - arrays

I need to distribute a large integer budget randomly among a small array with n elements, so that all elements in the array will have the same distribution and sum up to budget and each element in the array gets at least min.
I have an algorithm that runs in O(budget):
private int[] distribute(int budget, int n, int min) {
int[] subBudgets = new int[n];
for (int i = 0; i < n; i++) {
subBudgets[i] = min;
}
budget -= n * min;
while (budget > 0) {
subBudgets[random.nextInt(n)]++;
budget--;
}
return subBudgets;
}
However, when budget increases, it can be very expensive. Is there any algorithm that runs in O(n) or even better?

First generate n random numbers x[i], sum them up and then divide budget by the sum and you will get k. Then assign k*x[i] to each array element. It is simple and O(n).
If you want there at least min value in each element you can modify above algorithm by filling all elements by min (or use k*x[i] + min) and subcontracting n*min from budget before starting above algorithm.
If you need working with integers you can approach problem by using real value k and rounding k*x[i]. Then you have to track accumulating rounding error and add or subtract accumulated error from calculated value if it reach whole unit. You have to also assign remaining value into last element to reach whole budget.
P.S.: Note this algorithm can be used with easy in pure functional languages. It is reason why I like this whole family of algorithms generating random numbers for each member and then do some processing afterward. Example of implementation in Erlang:
-module(budget).
-export([distribute/2, distribute/3]).
distribute(Budget, N) ->
distribute(Budget, N, 0).
distribute(Budget, N, Min) when
is_integer(Budget), is_integer(N), N > 0,
is_integer(Min), Min >= 0, Budget >= N*Min ->
Xs = [random:uniform() || _ <- lists:seq(1,N) ],
Rest = Budget - N*Min,
K = Rest / lists:sum(Xs),
F = fun(X, {Bgt, Err, Acc}) ->
Y = X*K + Err,
Z = round(Y),
{Bgt - Z, Y - Z, [Z + Min | Acc]}
end,
{Bgt, _, T} = lists:foldl(F, {Rest, 0.0, []}, tl(Xs)),
[Bgt + Min | T].
Same algorithm in C++ (?? I dunno.)
private int[] distribute(int budget, int n, int min) {
int[] subBudgets = new int[n];
double[] rands = new double[n];
double k, err = 0, sum = 0;
budget -= n * min;
for (int i = 0; i < n; i++) {
rands[i] = random.nextDouble();
sum += rands[i];
}
k = (double)budget/sum;
for (int i = 1; i < n; i++) {
double y = k*rands[i] + err;
int z = floor(y+0.5);
subBudgets[i] = min + z;
budget -= z;
err = y - z;
}
subBudgets[0] = min + budget;
return subBudgets;
}

Sampling from the Multinomial Distribution
The way that you are currently distributing the dollars left over after min has been given to each subbudget involves performing a fixed number budget of random "trials", where on each trial you randomly select one of n categories, and you want to know how many times each category is selected. This is modeled by a multinomial distribution with the following parameters:
Number of trials (called n on the WP page): budget
Number of categories (called k on the WP page): n
Probability of category i in each trial, for 1 <= i <= n: 1/n
The way you are currently doing it is a good way if the number of trials is around the same size as the number of categories, or less. But if the budget is large, there are other more efficient ways of sampling from this distribution. The easiest way I know of is to notice that a multinomial distribution with k categories can be repeatedly decomposed into binomial distributions by grouping categories together: instead of directly how many selections there are for each of the k categories, we express this as a sequence of questions: "How to split the budget between the first category and the other k-1?" We next ask "How to split the remainder between the second category and the other k-2?", etc.
So the top level binomial has category (subbudget) 1 vs. everything else. Decide the number of dollars that go to subbudget 1 by taking 1 sample from a binomial distribution with parameters n = budget and p = 1/n (how to do this is described here); this will produce some number 0 <= x[1] <= n. To find the number of dollars that go to subbudget 2, take 1 sample from a binomial distribution on the remaining money, i.e. using parameters n = budget - x[1] and p = 1/(n-1). After getting subbudget 2's amount x[2], subbudget 3's will be found using parameters n = budget - x[1] - x[2] and p = 1/(n-2), and so on.

Integrating #Hynek -Pichi- Vychodil's idea and my original algorithm, I came up with the following algorithm that runs in O(n) and all rounding errors are uniformly distributed to the array:
private int[] distribute(int budget, int n, int min) {
int[] subBudgets = new int[n];
for (int i = 0; i < n; i++) {
subBudgets[i] = min;
}
budget -= n * min;
if (budget > 3 * n) {
double[] rands = new double[n];
double sum = 0;
for (int i = 0; i < n; i++) {
rands[i] = random.nextDouble();
sum += rands[i];
}
for (int i =0; i < n; i++) {
double additionalBudget = budget / sum * rands[i];
subBudgets[i] += additionalBudget;
budget -= additionalBudget;
}
}
while (budget > 0) {
subBudgets[random.nextInt(n)]++;
budget--;
}
return subBudgets;
}

Let me demonstrate my algorithm using an example:
Assume budget = 100, n = 5, min = 10
Initialize the array to:
[10, 10, 10, 10, 10] => current sum = 50
Generate a random integer ranging from 0 to 50 (50 is the result of budget - current sum):
Say the random integer is 20 and update the array:
[30, 10, 10, 10, 10] => current sum = 70
Generate a random integer ranging from 0 to 30 (30 is the result of budget - current sum):
Say the random integer is 5 and update the array:
[30, 15, 10, 10, 10] => current sum = 75
Repeat the process above and the last element is whatever is left.
Finally, shuffle the array to get the final result.

Related

Minimum number of operations to make pair sums of array equal

You are given a list of integers nums of even length. Consider an operation where you pick any number in nums and update it with a value between [1, max(nums)]. Return the number of operations required such that for every i, nums[i] + nums[n - 1 - i] equals to the same number. The problem can be solved greedily.
Note: n is the size of the array and max(nums) is the maximum element in nums.
For example: nums = [1,5,4,5,9,3] the expected operations are 2.
Explanation: The maxnums is 9, so I can change any element of nums to any number between [1, 9] which costs one operation.
Choose 1 at index 0 and change it to 6
Choose 9 at index 4 and change it to 4.
Now this makes the nums[0] + nums[5] = nums[1] + nums[4] = nums[2] + nums[3] = 9. We had changed 2 numbers and it cost us 2 operations which is the minimum for this input.
The approach that I've used is to find the median of the sums and use that to find the number of operations greedily.
Let us find the all the sums of the array based on the given condition.
Sums can be calculated by nums[i] + nums[n-1-i].
Let i = 0, nums[0] + nums[6-1-0] = 4.
i = 1, nums[1] + nums[6-1-1] = 14.
i = 2, nums[2] + nums[6-1-2] = 9.
Store these sums in an array and sort it.
sums = [4,9,14] after sorting. Now find the median from sums which is 9 as it is the middle element.
Now I use this median to equalize the sums and we can find the number of operations. I've also added the code that I use to calculate the number of operations.
int operations = 0;
for(int i=0; i<nums.size()/2; i++) {
if(nums[i] + nums[nums.size()-1-i] == mid)
continue;
if(nums[i] + nums[nums.size()-1-i] > mid) {
if(nums[i] + 1 <= mid || 1 + nums[nums.size()-1-i] <= mid) {
operations++;
} else {
operations += 2;
}
} else if (maxnums + nums[nums.size()-1-i] >= mid || nums[i] + maxnums >= mid) {
operations++;
} else {
operations += 2;
}
}
The total operations for this example is 2 which is correct.
The problem here is that, for some cases choosing the median gives the wrong result. For example, the nums = [10, 7, 2, 9, 4, 1, 7, 3, 10, 8] expects 5 operations but my code gives 6 if the median (16) was chosen.
Is choosing the median not the most optimal approach? Can anyone help provide a better approach?
I think the following should work:
iterate pairs of numbers
for each pair, calculate the sum of that pair, as well as the min and max sum that can be achieved by changing just one of the values
update a dictionary/map with -1 when starting a new "region" requiring one fewer change, and +1 when that region is over
iterate the boundaries in that dictionary and update the total changes needed to find the sum that requires the fewest updates
Example code in Python, giving 9 as the best sum for your example, requiring 5 changes.
from collections import defaultdict
nums = [10, 7, 2, 9, 4, 1, 7, 3, 10, 8]
m = max(nums)
pairs = [(nums[i], nums[-1-i]) for i in range(len(nums)//2)]
print(pairs)
score = defaultdict(int)
for a, b in map(sorted, pairs):
low = a + 1
high = m + b
score[low] -= 1
score[a+b] -= 1
score[a+b+1] += 1
score[high+1] += 1
print(sorted(score.items()))
cur = best = len(nums)
num = None
for i in sorted(score):
cur += score[i]
print(i, cur)
if cur < best:
best, num = cur, i
print(best, num)
The total complexity of this should be O(nlogn), needing O(n) to create the dictionary, O(nlogn) for sorting, and O(n) for iterating the sorted values in that dictionary. (Do not use an array or the complexity could be much higher if max(nums) >> len(nums))
(UPDATED receiving additional information)
The optimal sum must be one of the following:
a sum of a pair -> because you can keep both numbers of that pair
the min value of a pair + 1 -> because it is the smallest possible sum you only need to change 1 of the numbers for that pair
the max value of a pair + the max overall value -> because it is the largest possible sum you only need to change 1 of the numbers for that pair
Hence, there are order N possible sums.
The total number of operations for this optimal sum can be calculated in various ways.
The O(N²) is quite trivial. And you can implement it quite easily if you want to confirm other solutions work.
Making it O(N log N)
getting all possible optimal sums O(N)
for each possible sum you can calculate occ the number of pairs having that exact sum and thus don't require any manipulation. O(N)
For all other pairs you just need to know if it requires 1 or 2 operations to get to that sum. Which is 2 when it is either impossible if the smallest of the pair is too big to reach sum with the smallest possible number or when the largest of the pair is too small to reach the sum with the largest possible number. Many data structures could be used for that (BIT, Tree, ..). I just used a sorted list and applied binary search (not exhaustively tested though). O(N log N)
Example solution in java:
int[] nums = new int[] {10, 7, 2, 9, 4, 1, 7, 3, 10, 8};
// preprocess pairs: O(N)
int min = 1
, max = nums[0];
List<Integer> minList = new ArrayList<>();
List<Integer> maxList = new ArrayList<>();
Map<Integer, Integer> occ = new HashMap<>();
for (int i=0;i<nums.length/2;i++) {
int curMin = Math.min(nums[i], nums[nums.length-1-i]);
int curMax = Math.max(nums[i], nums[nums.length-1-i]);
min = Math.min(min, curMin);
max = Math.max(max, curMax);
minList.add(curMin);
maxList.add(curMax);
// create all pair sums
int pairSum = nums[i] + nums[nums.length-1-i];
int currentOccurences = occ.getOrDefault(pairSum, 0);
occ.put(pairSum, currentOccurences + 1);
}
// sorting 0(N log N)
Collections.sort(minList);
Collections.sort(maxList);
// border cases
for (int a : minList) {
occ.putIfAbsent(a + max, 0);
}
for (int a : maxList) {
occ.putIfAbsent(a + min, 0);
}
// loop over all condidates O(N log N)
int best = (nums.length-2);
int med = max + min;
for (Map.Entry<Integer, Integer> entry : occ.entrySet()) {
int sum = entry.getKey();
int count = entry.getValue();
int requiredChanges = (nums.length / 2) - count;
if (sum > med) {
// border case where max of pair is too small to be changed to pair of sum
requiredChanges += countSmaller(maxList, sum - max);
} else if (sum < med) {
// border case where having a min of pair is too big to be changed to pair of sum
requiredChanges += countGreater(minList, sum - min);
}
System.out.println(sum + " -> " + requiredChanges);
best = Math.min(best, requiredChanges);
}
System.out.println("Result: " + best);
}
// O(log N)
private static int countGreater(List<Integer> list, int key) {
int low=0, high=list.size();
while(low < high) {
int mid = (low + high) / 2;
if (list.get(mid) <= key) {
low = mid + 1;
} else {
high = mid;
}
}
return list.size() - low;
}
// O(log N)
private static int countSmaller(List<Integer> list, int key) {
int low=0, high=list.size();
while(low < high) {
int mid = (low + high) / 2;
if (list.get(mid) < key) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
Just to offer some theory -- we can easily show that the upper bound for needed changes is n / 2, where n is the number of elements. This is because each pair can be made in one change to anything between 1 + C and max(nums) + C, where C is any of the two elements in a pair. For the smallest C, we can bind max(nums) + 1 at the highest; and for the largest C, we can bind 1 + max(nums) at the lowest.
Since those two bounds at the worst cases are equal, we are guaranteed there is some solution with at most N / 2 changes that leaves at least one C (array element) unchanged.
From that we conclude that an optimal solution either (1) has at least one pair where neither element is changed and the rest require only one change per pair, or (2) our optimal solution has n / 2 changes as discussed above.
We can therefore proceed to test each existing pair's single or zero change possibilities as candidates. We can iterate over a sorted list of two to three possibilities per pair, labeled with each cost and index. (Other authors on this page have offered similar ways and code.)

Calculate the maximal even cost subarray

I am new to Algorithms and Competitive Programming. I am learning about Dynamic programming and I have a problem as below:
Given an array with n numbers. Define a sub-array is a[i, j] = {a[i], a[i + 1], ..., a[j]}, in other words, elements must be contiguous.
The problem is the find the maximum weight of a sub-array such that
that weight is an even number.
The input is 2 <= n <= 1000000; -100 <= a[i] <= 100
Sample test:
5
-2 1 -4 4 9
Output: 10
For this problem, I can do brute force but with a large value of n, I can not do it with the time limit is 1 second. Therefore, I want to change it to Dynamic programming.
I have an idea but I do not know if it works. I think I can divide this problem into two sub-problems. For each element/number, I consider if it is odd/even and then find the largest sum with its corresponding property (odd + odd or even + even to get a even sum). However, that is just what I think and I really need your help.
Here is C++ algorithm with O(n) time complexity:
const int Inf = 1e9;
int main() {
int n = 5;
vector<int> inputArray = {-2, 1, -4, 4, 9};
int minEvenPrefixSum = 0, minOddPrefixSum = Inf;
bool isOddPrefixSumFound = false;
int prefixSum = 0, answer = -Inf;
for(int i = 0; i < n; ++i) {
prefixSum += inputArray[i];
if(abs(prefixSum) % 2 == 0) {
answer = max(answer, prefixSum - minEvenPrefixSum);
minEvenPrefixSum = min(minEvenPrefixSum, prefixSum);
} else {
if(isOddPrefixSumFound) {
answer = max(answer, prefixSum - minOddPrefixSum);
}
isOddPrefixSumFound = true;
minOddPrefixSum = min(minOddPrefixSum, prefixSum);
}
}
if(answer == -Inf) {
cout << "There is no subarray with even sum";
} else {
cout << answer;
}
}
Explanation:
As #nico-schertler mentioned in commentary this task is very similar with more basic problem of the maximum-sum contiguous sub array. How to solve basic task with O(n) time complexity you can read here.
Now let's store not just one value of the minimum prefix sum, but two. One is for minimum even prefix sum, and the other is for minimum odd prefix sum. As a result, when we process the next number, we look at what the value of the prefix sum becomes. If it is even, we try to update the answer using the minimum even value of the prefix sum, in the other case using the minimum odd value of the prefix sum.

Time complexity finding n primes with trial division by all preceding primes

Problem : Finding n prime numbers.
#include<stdio.h>
#include<stdlib.h>
void firstnprimes(int *a, int n){
if (n < 1){
printf("INVALID");
return;
}
int i = 0, j, k; // i is the primes counter
for (j = 2; i != n; j++){ // j is a candidate number
for (k = 0; k < i; k++)
{
if (j % a[k] == 0) // a[k] is k-th prime
break;
}
if (k == i) // end-of-loop was reached
a[i++] = j; // record the i-th prime, j
}
return;
}
int main(){
int n;
scanf_s("%d",&n);
int *a = (int *)malloc(n*sizeof(int));
firstnprimes(a,n);
for (int i = 0; i < n; i++)
printf("%d\n",a[i]);
system("pause");
return 0;
}
My function's inner loop runs for i times (at the most), where i is the number of prime numbers below a given candidate number, and the outer loop runs for (nth prime number - 2) times.
How can I derive the complexity of this algorithm in Big O notation?
Thanks in advance.
In pseudocode your code is
firstnprimes(n) = a[:n] # array a's first n entries
where
i = 0
a = [j for j in [2..]
if is_empty( [j for p in a[:i] if (j%p == 0)] )
&& (++i) ]
(assuming the short-circuiting is_empty which returns false as soon as the list is discovered to be non-empty).
What it does is testing each candidate number from 2 and up by all its preceding primes.
Melissa O'Neill analyzes this algorithm in her widely known JFP article and derives its complexity as O( n^2 ).
Basically, each of the n primes that are produced is paired up with (is tested by) all the primes preceding it (i.e. k-1 primes, for the k th prime) and the sum of the arithmetic progression 0...(n-1) is (n-1)n/2 which is O( n^2 ); and she shows that composites do not contribute any term which is more significant than that to the overall sum, as there are O(n log n) composites on the way to n th prime but the is_empty calculation fails early for them.
Here's how it goes: with m = n log n, there will be m/2 evens, for each of which the is_empty calculation takes just 1 step; m/3 multiples of 3 with 2 steps; m/5 with 3 steps; etc.
So the total contribution of the composites, overestimated by not dealing with the multiplicities (basically, counting 15 twice, as a multiple of both 3 and 5, etc.), is:
SUM{i = 1, ..., n} (i m / p_i) // p_i is the i-th prime
= m SUM{i = 1, ..., n} (i / p_i)
= n log(n) SUM{i = 1, ..., n} (i / p_i)
< n log(n) (n / log(n)) // for n > 14,000
= n^2
The inequality can be tested at Wolfram Alpha cloud sandbox as Sum[ i/Prime[i], {i, 14000}] Log[14000.0] / 14000.0 (which is 0.99921, and diminishing for bigger n, tested up to n = 2,000,000 where it's 0.963554).
The prime number theorem states that asymptotically, the number of primes less than n is equal to n/log n. Therefore, your inner loop will run Theta of i * max =n / log n * n times (assuming max=n).
Also, your outer loop runs on the order of n log n times, making the total complexity Theta of n / log n * n * n log n = n^3. In other words, this is not the most efficient algorithm.
Note that there are better approximations around (e.g. the n-th prime number is closer to:
n log n + n log log n - n + n log log n / log n + ...
But, since you are concerned with just big O, this approximation is good enough.
Also, there are much better algorithms for doing what you're looking to do. Look up the topic of pseudoprimes, for more information.

Algorithm to find the factors of a given Number.. Shortest Method?

What could be the simplest and time efficient logic to find out the factors of a given Number.
Is there any algorithm that exist, based on the same.
Actually, my real problem is to find out the no. of factors that exist for a given Number..
So Any algorithm, please let me know on this..
Thanks.
Actually, my real problem is to find out the no. of factors that exist for a given Number..
Well, this is different. Let n be the given number.
If n = p1^e1 * p2^e2 * ... * pk^ek, where each p is a prime number, then the number of factors of n is (e1 + 1)*(e2 + 1)* ... *(ek + 1). More on this here.
Therefore, it is enough to find the powers at which each prime factor appears. For example:
read given number in n
initial_n = n
num_factors = 1;
for (i = 2; i * i <= initial_n; ++i) // for each number i up until the square root of the given number
{
power = 0; // suppose the power i appears at is 0
while (n % i == 0) // while we can divide n by i
{
n = n / i // divide it, thus ensuring we'll only check prime factors
++power // increase the power i appears at
}
num_factors = num_factors * (power + 1) // apply the formula
}
if (n > 1) // will happen for example for 14 = 2 * 7
{
num_factors = num_factors * 2 // n is prime, and its power can only be 1, so multiply the number of factors by 2
}
For example, take 18. 18 = 2^1 * 3*2 => number of factors = (1 + 1)*(2 + 1) = 6. Indeed, the 6 factors of 18 are 1, 2, 3, 6, 9, 18.
Here's a little benchmark between my method and the method described and posted by #Maciej. His has the advantage of being easier to implement, while mine has the advantage of being faster if change to only iterate over the prime numbers, as I have done for this test:
class Program
{
static private List<int> primes = new List<int>();
private static void Sieve()
{
bool[] ok = new bool[2000];
for (int i = 2; i < 2000; ++i) // primes up to 2000 (only need up to sqrt of 1 000 000 actually)
{
if (!ok[i])
{
primes.Add(i);
for (int j = i; j < 2000; j += i)
ok[j] = true;
}
}
}
private static int IVlad(int n)
{
int initial_n = n;
int factors = 1;
for (int i = 0; primes[i] * primes[i] <= n; ++i)
{
int power = 0;
while (initial_n % primes[i] == 0)
{
initial_n /= primes[i];
++power;
}
factors *= power + 1;
}
if (initial_n > 1)
{
factors *= 2;
}
return factors;
}
private static int Maciej(int n)
{
int factors = 1;
int i = 2;
for (; i * i < n; ++i)
{
if (n % i == 0)
{
++factors;
}
}
factors *= 2;
if (i * i == n)
{
++factors;
}
return factors;
}
static void Main()
{
Sieve();
Console.WriteLine("Testing equivalence...");
for (int i = 2; i < 1000000; ++i)
{
if (Maciej(i) != IVlad(i))
{
Console.WriteLine("Failed!");
Environment.Exit(1);
}
}
Console.WriteLine("Equivalence confirmed!");
Console.WriteLine("Timing IVlad...");
Stopwatch t = new Stopwatch();
t.Start();
for (int i = 2; i < 1000000; ++i)
{
IVlad(i);
}
Console.WriteLine("Total milliseconds: {0}", t.ElapsedMilliseconds);
Console.WriteLine("Timing Maciej...");
t.Reset();
t.Start();
for (int i = 2; i < 1000000; ++i)
{
Maciej(i);
}
Console.WriteLine("Total milliseconds: {0}", t.ElapsedMilliseconds);
}
}
Results on my machine:
Testing equivalence...
Equivalence confirmed!
Timing IVlad...
Total milliseconds: 2448
Timing Maciej...
Total milliseconds: 3951
Press any key to continue . . .
There is a large number of algorithms available - from simple trial devision to very sophisticated algorithms for large numbers. Have a look at Integer Factorization on Wikipedia and pick one that suits your needs.
Here is a short but inefficient C# implementation that finds the number of prime factors. If you need the number of factors (not prime factors) you have to store the prime factors with their multiplicity and calculate the number of factors afterwards.
var number = 3 * 3 * 5 * 7 * 11 * 11;
var numberFactors = 0;
var currentFactor = 2;
while (number > 1)
{
if (number % currentFactor == 0)
{
number /= currentFactor;
numberFactors++;
}
else
{
currentFactor++;
}
}
Here is a fruit of my short discussion with |/|ad :)
read given number in n
int divisorsCount = 1;
int i;
for(i = 2; i * i < n; ++i)
{
if(n % i == 0)
{
++divisorsCount;
}
}
divisorsCount *= 2;
if(i * i == n)
{
++divisorsCount;
}
Careful, this answer is not useful/fast for a single value of n.
Method 1:
You can get it in O(polylog(n)) if you maintain a look-up table (for the first prime factor of a number).
If gcd(a,b) == 1, then
no. of factors of a*b = (no. of factors of a) * (no. of factors of b)
Therefore, for a given number a*b, if gcd(a,b) != 1 then we can have two other numbers p and q where p = a and q = b/gcd(a,b). Thus, gcd(p,q) == 1. Now, we can recursively find the number of factors for p and q.
It will take only some small amount of efforts to ensure neither p nor q is 1.
P.S. This method is also useful when you need to know the number of factors of all numbers from 1 to n. It would be an order of O(nlogn + O(look-up table)).
Method 2: (I do not have ownership for this.)
If you have the look-up for first prime factor till n, then you can know it's all prime factors in O(logn) and thus find the number of factors from them.
P.S. Google 'Factorization in logn' for better explanation.
Euclid's Algorithm should suffice.

Find buy/sell prices in array of stock values to maximize positive difference

Got this question in an interview today, and its optimized solution stopped me cold (which blows, because I really wanted to work for this company...)
Given a single array of real values, each of which represents the stock value of a company after an arbitrary period of time, find the best buy price and its corresponding best sell price (buy low, sell high).
To illustrate with an example, let's take the stock ticker of Company Z:
55.39 109.23 48.29 81.59 105.53 94.45 12.24
Important to note is the fact that the array is "sorted" temporally - i.e. as time passes, values are appended to the right end of the array. Thus, our buy value will be (has to be) to the left of our sell value.
(in the above example, the ideal solution is to buy at 48.29 and sell at 105.53)
I came up with the naive solution easily enough with O(n2) complexity (implemented in java):
// returns a 2-element array: first element is the index in the argument array
// of the best buying price, and the second element is the index of the best
// selling price which, collectively, maximize the trading return
//
// if there is no favorable trading (e.g. prices monotonically fall), null is returned
public int[] maximizeReturn(ArrayList<Double> prices) {
int [] retval = new int[2];
int BUY = 0, SELL = 1;
retval[BUY] = retval[SELL] = -1; // indices of buy and sell prices, respectively
for (int i = 0; i < prices.size(); i++) {
for (int j = i + 1; j < prices.size(); j++) {
double difference = prices.get(j).doubleValue() -
prices.get(i).doubleValue();
if (difference > 0.0) {
if (retval[BUY] < 0 || difference > prices.get(retval[SELL]).doubleValue() -
prices.get(retval[BUY]).doubleValue()) {
retval[BUY] = i;
retval[SELL] = j;
}
}
}
}
return (retval[BUY] > 0 ? retval : null);
}
Here's where I screwed up: there's a linear time O(n) solution, and I completely bombed in trying to figure it out (yeah, I know, FAIL). Does anyone know how to implement the linear time solution? (any language you're comfortable with) Thanks!
Edit
I suppose, for anyone interested, I just received word today that I didn't get the job for which I interviewed where they asked me this question. :(
In C#:
static void Main(string[] args)
{
double[] values = new double[7]{55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24};
double max = double.MinValue, maxDiff = double.MinValue, diff = 0;
for (int i = 1; i < values.Length; i++)
{
if (values[i] > values[i - 1])
{
//trending upward, append to existing differential
diff += values[i] - values[i - 1];
}
else
{
//trending downward, reset the diff
diff = 0;
}
if (diff > maxDiff)
{
maxDiff = diff;
max = values[i];
}
}
Console.WriteLine("Buy at {0}; Sell at {1}", max - maxDiff, max);
}
EDIT: New algo based on #Joe's failing test case -- Nice Catch BTW! It's also the same answer as #Doug T's now...
static void Main(string[] args)
{
double[] values = new double[8] { 55.39, 109.23, 48.29, 81.59, 81.58, 105.53, 94.45, 12.24 };
double max = double.MinValue, maxDiff = double.MinValue, diff = 0;
double bottom = values[0];
for (int i = 1; i < values.Length; i++)
{
diff += values[i] - values[i - 1];
if (diff > maxDiff)
{
maxDiff = diff;
max = values[i];
}
if (values[i] < bottom)
{
bottom = values[i];
diff = 0;
}
}
Console.WriteLine("Buy at {0}; Sell at {1}", max - maxDiff, max);
}
Here's an attempt (C++). Basically everytime I track a new top, I try to see if thats the best profit thusfar. I know that the "bottom" must have been discovered earlier. At that point I remember the top, bottom, and the current max profit. If a new bottom is discovered later, its AFTER the current top, so we must reset top and see if a slightly lower "top" can yield better profit.
#include <iostream>
int main()
{
double REALLY_BIG_NO = 1e99;
double bottom = REALLY_BIG_NO; // arbirtrary large number
double currBestBuy = 0.0;
double top = 0.0;
double currBestSell = 0.0;
double profit = 0.0;
// array of prices
double prices[] = {10.50, 55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24, 152.0, 2, 170.0};
int numPrices = 10;// number of prices
for (int i = 0; i < numPrices; ++i)
{
if (prices[i] < bottom)
{
bottom = prices[i];
// reset the search on a new bottom
top = 0.0;
}
else if (prices[i] > top)
{
top = prices[i];
// calculate profit
double potentialProfit = (top - bottom);
if (potentialProfit > profit &&
bottom != REALLY_BIG_NO)
{
profit = potentialProfit;
currBestSell = top;
currBestBuy = bottom;
}
}
}
std::cout << "Best Buy: " << currBestBuy << "Best Sell: " << currBestSell << std::endl;
}
So far I've played around with a bunch of different input sets, and so far I haven't had any problems... (let me know if you test this and see anything wrong)
I highly recommend using Austin Salonen's updated answer to this question and adapting it to your language.
The idea is simple. Keep two pointers, lo and hi.
Do a Foor loop
if price is higher than hi, update hi = price, continue
if the price is lower than hi. Then lo and hi is one of possible candidates. Calculate the profit, store it if it's bigger than previous profits and reset lo, hi to price
def getBestProfit(prices):
lo = hi = profit = 0
for price in prices:
if lo == 0 and hi == 0:
lo = hi = price
if price > hi:
hi = price
if price < low:
tmpProfit = hi - lo
if tmpProfit > profit:
profit = tmpProfit
lo = hi = price
return profit
That's it
void getBestTime (int stocks[], int sz, int &buy, int &sell){
int min = 0;
int maxDiff = 0;
buy = sell = 0;
for (int i = 0; i < sz; i++)
{
if (stocks[i] < stocks[min])
{
min = i;
}
int diff = stocks[i] - stocks[min];
if (diff > maxDiff)
{
buy = min;
sell = i;
maxDiff = diff;
}
}}
Just in case you prefer this answer. I found it in another web, but still.
source:http://leetcode.com/2010/11/best-time-to-buy-and-sell-stock.html
public void profit(float stock[], int arlen ){
float buy = stock[0];
float sell = stock[arlen-1];
int bi = 0;
int si = arlen - 1;
for( int i = 0; i < arlen && bi < si ; i++){
if( stock[i] < buy && i < si){
buy = stock[i];
bi = i;
}
if(stock[arlen - i - 1] > sell && (arlen - i -1) > bi){
sell = stock[arlen - i - 1];
si = arlen - i - 1;
}
}
System.out.println(buy+" "+sell);
}
I really have to point out as an interview question expecting you to solve it as O(n) is borderline absurd. Interview questions are meant to prove you can solve a problem, which you were able to solve it. The fact you solved it in O(N^2) vs O(N) should be irrelevant. If a company would pass over hiring you for not solving this in O(N) that's probably not a company you would have wanted to work at anyway.
I'd like to describe how I approached this problem to make it easier to understand my code:
(1) For each day, if I had to sell my stock on that day, what would be the minimum amount I could have paid to buy it? Essentially, I'm keeping track of minimum price before that day
(2) For each day, if I were to sell on that day, how much am I earning? (Stock price on that day - minimum price)
This shows that I have to keep track of two things: (1) minimum stock price so far (2) best earning so far.
The problem becomes choosing which day to sell. I will sell on the day that will give me the best earning. Here is my Java code:
public static void findBestDeal(double [] stocks) {
double minsofar = stocks[0];
double bestsofar = 0.0;
for(int i=1; i< stocks.length; i++) {
// What is the cheapest price to buy it if I'm going to sell it today
if(stocks[i-1] < minsofar) {
minsofar = stocks[i-1];
}
// How much do I earn if I sell it on ith day?
double current_deal = stocks[i] - minsofar;
// Is selling today better?
if(current_deal > bestsofar) {
bestsofar = current_deal;
}
}
System.out.println("Found the best deal: " + bestsofar + " (Bought at " + minsofar + " and sold at " + (minsofar+bestsofar) + ")");
}
Here is my O(n) implementation for this. I am using a change array to calculate the max profit and buy and sell dates.
Your comments on this are welcome.
#include<stdafx.h>
#include<stdio.h>
int main()
{
//int arr[10] = {15, 3, 5,9,10,1,6,4,7,2};
int arr[7] = {55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24};
int change[7];
int n=7;
for(int i=1;i<=n;i++)
{
change[i] = arr[i]- arr[i-1];
}
int i=0,index = 0;
int sum = 0;
int maxsum = 0;
int startpos = 0;
int endpos = 0;
while(index < n)
{
sum = sum + change[index];
if(maxsum < sum)
{
maxsum = sum;
startpos = i;
endpos = index;
}
else if (sum<0) // negative number ,set sum to zero
{
sum = 0;
i=index+1;
}
index++;
}
printf("max profit is%d %d %d", maxsum , startpos, endpos+1 );
}
In my effort to learn Go, and also to rake my brain on this one, here is my attempt.
func GetMaxProfit2(prices []float64) (float64, float64) {
var min, max, pmin, pmax int
for i, v := range prices {
if v - prices[min] > prices[max] - prices[min] {
pmax = max
max = i
}
// Reset the max when min is updated.
if v < prices[min] {
pmin = min
min = i
pmax = max
max = i
}
}
// If min is ahead of max, reset the values back
if min >= max {
min = pmin
max = pmax
}
return prices[min], prices[max]
}
Here is my attempt using Javascript. The script computes the answer in O(N):
//Main Stock Array
var stock = [15, 20, 0, 3, 30, 45, 67, 92, 1, 4, 99];
//Setup initial variable state
var ans = {}, tmp = {}; //These are just for namespacing / syntatic sugar
ans.minVal = stock[0];
ans.minInd = 0;
ans.maxDiff = stock[1] - stock[0];
ans.maxInd = 1;
tmp.minInd = ans.minInd;
tmp.minVal = ans.minVal;
//Basically we iterate throught the array. If we find a new low, we start tracking it. Otherwise we compare the current index against the previously found low
for(i = 1; i <= stock.length-1; i++) {
if(tmp.minVal > stock[i]) {
tmp.minVal = stock[i];
tmp.minInd = i;
} else {
ans.diff = stock[i] - stock[tmp.minInd];
if(ans.diff > ans.maxDiff) { //Looks like we found a new maxDifference. Lets log the indexes
ans.maxDiff = ans.diff;
ans.maxInd = i;
ans.minInd = tmp.minInd;
ans.minVal = tmp.minVal;
}
}
}
document.write('You should buy your stocks on day ' + ans.minInd + ' and sell on day ' + ans.maxInd);
This is a C solution that actually works:
void bestBuySell()
{
double prices[] = {10.50, 10.0, 3.0, 194.0, 55.39, 2.0, 109.23, 48.29, 81.59, 105.53, 94.45, 191.0, 200.0, 12.24};
int arrSize = 14;
double bestBuy = prices[0], bestSell = prices[1], bestPotentialBuy = prices[0];
double potentialProfit = prices[1] - prices[0];
for(int i = 1; i < (arrSize-1); i++)
{
if(prices[i] < bestBuy)
bestPotentialBuy = prices[i];
if((prices[i+1] - bestPotentialBuy) > potentialProfit)
{
bestBuy = bestPotentialBuy;
bestSell = prices[i+1];
potentialProfit = prices[i+1] - bestPotentialBuy;
}
}
printf( "bestBuy %f bestSell %f\n", bestBuy, bestSell );
}
1.We cant simply take the least amount among the values as " Best Buy" and the max amount as "Best Sell" because "Sell" has to happen after "Buy".
2.We must not treat the recorded minimum as the "Best Buy" because the subsequent days may have stock values whose difference with the recorded minimum may yield profit which could be less than the "recorded profit".
3.Best Buy and Best Sell is treated as a single variant,because it is the positive difference between these values that makes max profit.
4.Since any recorded minimum in the past is a potential candidate for buying,the max profit condition must always be checked against the recorded minimum and the current day's stock price.So we always have to keep track of recorded minimum,but just the presence of recorded minimum doesn't constitute "Best Buy" because of reason number 2.
Now have the below code which executes in O(n) times will make sense.
public class BestStockBuyAndSell {
public static void main(String[] args) {
double[] stockPrices = {55.39,109.23,48.29,81.59,105.53,94.45,12.24};
int [] bestBuySellIndex = maxProfit(stockPrices);
System.out.println("Best Buy At "+stockPrices[bestBuySellIndex[0]]);
System.out.println("Best Sell At "+stockPrices[bestBuySellIndex[1]]);
System.out.println("Max Profit = "+(stockPrices[bestBuySellIndex[1]]-stockPrices[bestBuySellIndex[0]]));
}
public static int[] maxProfit(double[] stockPrices)
{
int bestBuy=0;
int bestSell=0;
int[] bestCombination ={bestBuy,bestSell};
double recordedMinimum = stockPrices[bestBuy];
int recordedMinimuIndex = bestBuy;
double bestProfitSofar = stockPrices[bestSell] - stockPrices[bestBuy];
for(int i=1;i<stockPrices.length;i++)
{
if(stockPrices[i] - recordedMinimum > bestProfitSofar)
{
bestProfitSofar = stockPrices[i] - recordedMinimum;
bestSell = i;
bestBuy = recordedMinimuIndex;
}
if(stockPrices[i] < recordedMinimum)
{
recordedMinimuIndex = i;
recordedMinimum = stockPrices[i];
}
}
bestCombination[0] = bestBuy;
bestCombination[1] = bestSell;
return bestCombination;
}
}
I came up with following algorithm for this problem, seems to work for all inputs. Also, If the Stock value keeps droping, the program would output not to buy this stock:
public class GetMaxProfit
{
double minValue = -1, maxValue = -1;
double maxDiff = 0;
public void getProfit(double [] inputArray){
int i=0, j=1;
double newDiff = 0;
while(j<inputArray.length){
newDiff = inputArray[j]-inputArray[i];
if(newDiff > 0){
if(newDiff > this.maxDiff){
this.minValue = inputArray[i];
this.maxValue = inputArray[j];
this.maxDiff = newDiff;
}
}
else{
i = j;
}
j++;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
GetMaxProfit obj = new GetMaxProfit();
obj.getProfit(new double[]{55.39, 19.23, 14.29, 11.59, 10.53, 9.45, 1.24});
if(obj.minValue != -1 && obj.maxValue != -1){
System.out.println("Buy Value for the input: "+obj.minValue);
System.out.println("Sell Value for the input: "+obj.maxValue);
System.out.println("Best profit for the input: "+obj.maxDiff);
}
else
System.out.println("Do Not Buy This STOCK!!);
}
}
Is there any catch you could find in this? It's time complexity is O(N)
Here is my solution, same as #Doug T. except I am also keeping track of the day in an index. Please provide feedback.
int prices[] = {4,4,5,6,2,5,1,1};
//int prices[] = {100, 180, 260, 310, 40, 535, 695};
int currentBestSellPrice=0;
int currentBestBuyPrice=0;
int lowindex=0;
int highindex=0;
int low=prices[0];
int high=prices[0];
int profit=0;
int templowindex=0;
for(int i=0; i< prices.length;i++)
{
// buy low
if(prices[i] < low && i+1 < prices.length)
{
low = prices[i];
templowindex=i;
high=0;
}
// sell high
else if(prices[i] > high)
{
high = prices[i];
int potentialprofit = (high-low);
if(potentialprofit > profit)
{
profit = potentialprofit;
currentBestSellPrice = high;
currentBestBuyPrice = low;
highindex=i;
lowindex=templowindex;
}
}
}
System.out.println("Best Buy Price : "+ currentBestBuyPrice + " on day "+ lowindex);
System.out.println("Best Sell Price : "+ currentBestSellPrice+ " on day "+ highindex );
F# solution for those who interested in functional take on this. I wouldn't say though it's that much different.
let start, _, profit =
[55.39; 109.23; 48.29; 81.59; 81.58; 105.53; 94.45; 12.24 ]
|> Seq.fold (fun (start,newStart,profit) i ->
let start = defaultArg start i
let newStart = defaultArg newStart i
let newProfit = i - newStart
if profit < newProfit
then Some newStart, Some newStart,newProfit
else if start > i
then Some start, Some i, profit
else Some start,Some newStart,profit) (None,None, 0.0)
printf "Best buy: %f; Best sell: %f" start.Value (start.Value + profit)
Output:
Best buy: 48.290000; Best sell: 105.530000
Here is my solution in Ruby:
values = [55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24]
max_diff = 0
diff = 0
min = values[0]
max = 0
values.each_with_index do |value, index = 1|
# get an array of the previous values before the current one
lag_values = values[0..index]
# get the minimum of those previous values
min_lag_value = lag_values.min
# difference between current value and minimum of previous ones
diff = values[index].to_i - min_lag_value.to_i
# if current difference is > previous max difference, then set new values for min, max_diff, and max
if diff > max_diff
max_diff = diff
min = min_lag_value
max = values[index]
end
end
min # => 48.29
max # => 105.3
max_diff # => 57
Cheers
I got 100% for the same, here you go.
public int solution(int[] A) {
if (A == null || A.length<=1){
return 0;
}
int minValue = Math.min(A[0], A[1]);
int profit = A[1] - A[0];
for (int i = 2; i < A.length; i++) {
minValue = Math.min(minValue, A[i]);
profit = Math.max(A[i] - minValue,profit);
}
return profit > 0 ? profit : 0;
}
The way I thought about this was, for every index i what would be the ideal index be for selling this stock? This is of course, the index of the maximum value after i. This reduces our problem to finding the maximum element after index i for each i in [1 ... n] If we could do that in O(n) time, then we could find the best choice amongst those and report it.
A way to do this is to start traversing from the end of the array, maintaining two variables, one to save the largest element we have encountered so far max_till_now, and one to save the maximum profit we could get till now, profit. This is just so that we can do this in one pass. We could also use extra space and for each element i, store the index of the largest element in the range [i + 1 ... n] for it and then find the maximum profit.
Here's my python code:
def buyLowSellHigh(L):
length = len(L)
profit = 0
max_till_now = L[length - 1]
for i in xrange(length - 2, -1, -1):
if L[i] > max_till_now: max_till_now = L[i]
else:
if max_till_now - L[i] > profit: profit = max_till_now - L[i]
return profit
Another Ruby solution:
# Here's some examples. Please feel free to give your new test.
values = [55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24]
# values = [5, 6, 4, 7, 9, 8, 8]
# values = [5, 10, 4, 6, 7]
# values = [5, 10, 4, 6, 12]
# values = [1, 2, 3, 4, 5]
# Initialize parameters.
min = values[0]
best_buy_time = values[0]
best_sell_time = values[0]
max_profit = 0
# This solution is based on comparing previous k elements and k+1 one.
# The runtime is O(n) and it only use O(1) auxiliary storage.
values.each_with_index do |value, index = 1|
# Check value in this turn.
puts value
# Check current value is bigger than min or not.
# If not, we find the new min.
if value <= min
min = value
# If current value is bigger than min and
# (value - min) is bigger than previous max_profit,
# set new best_buy_time, best_sell_time & max_profit.
else
if value - min >= max_profit
best_buy_time = min
best_sell_time = value
max_profit = value - min
end
end
end
# Let's see about the result.
puts "\nbest_buy_time: ", best_buy_time, "\nbest_sell_time: ", best_sell_time, "\nmax_profit: ", max_profit
what about this?
min = 100000000
max = 0
for elem in inp:
if elem < min:
min = elem
tempMax = elem-min
if tempMax > max:
max = tempMax
print(max)
Solution in javascript
var stockArr = [13931, 9889, 987, 4, 89, 100];
function getBestTime(sortedArr) {
var min = 0;
var buyIndx = 0;
var saleIndx = 0;
var maxDiff = 0;
for (var i = 0; i < stockArr.length; i++) {
if (stockArr[i] < stockArr[min]) {
min = i;
}
var diff = stockArr[i] - stockArr[min];
if (diff > maxDiff) {
buy = min;
sale = i;
maxDiff = diff;
}
}
return {
buy:buy+1,
sale:sale+1,
diff:maxDiff
}
}
console.log(getBestTime(stockArr));
Heres a javascript solution..
function getMax(arr){
//we need more than at least 3 ints to be able to do this
if(arr.length <= 1) return arr;
// get the minimum price we can sell at to make a profit
var min = arr[0];
//get the first potential maximum profit
var max = arr[1] - arr[0];
//while looping through we must get a potential value,
//we can then compare that using the math.max using the maximum
//and the potential prices that we have seen. Once the loop runs the ouput here should be 6!
for(var i = 1; i < arr.length; ++i){
var current = arr[i];
var potential = current - min;
max = Math.max(max, potential);
min = Math.min(min, current);
}
return max;
}
console.log(getMax([10, 7, 5, 8, 11, 9]));
Runtime on this is O(n)
Solution in scala :
Example : [ 7, 2, 5, 6, 1, 3, 6, 4 ]
Keep a pointer to the last minimum stock price(lastStockPrice) and compare it to the current stock price. When you reach a point where the current stock price < last minimun stock price, you update the lastStockPrice.
While looping through the array, keep a track of the max difference (profit) between the currentPrice and the lastStockPrice as the profit can change when you update the lastStockPrice.
The below scala code works in O(n) time and takes a constant amount of space.
object Solution {
def maxProfit(prices: Array[Int]): Int = {
var lastStockPrice = Int.MaxValue
var maxProfit = 0
for(currentPrice <- prices){
if(currentPrice < lastStockPrice){
lastStockPrice = currentPrice;
}else if(currentPrice - lastStockPrice > maxProfit){
maxProfit = currentPrice - lastStockPrice;
}
}
maxProfit
}
}
The logic to solve this problem is same as "max subarray problem" using Kadane's Algorithm. Since no body has mentioned this so far, I thought it's a good thing for everybody to know.
All the straight forward solution should work, but if the interviewer twists the question slightly by giving the difference array of prices, Ex: for {1, 7, 4, 11}, if he gives {0, 6, -3, 7}, you might end up being confused.
Here, the logic is to calculate the difference (maxCur += prices[i] - prices[i-1]) of the original array, and find a contiguous subarray giving maximum profit. If the difference falls below 0, reset it to zero.
class Solution:
def maxProfit(self, prices: List[int]) -> int:
_currmax = 0
_globalMax = 0
for i in range(1,len(prices)):
_currmax = max(_currmax+(prices[i]-prices[i-1]),0)
_globalMax = max(_globalMax,_currmax)
return _globalMax

Resources