Máximo beneficio de venta individual

Supongamos que se nos da una matriz de n enteros que representan los precios de las acciones en un solo día. Queremos encontrar un par (buyDay, sellDay) , con buyDay ≤ sellDay , de manera que si compramos las acciones en buyDay y lo vendamos en sellDay , maximicemos nuestras ganancias.

Claramente hay una solución O (n 2 ) para el algoritmo probando todos los pares posibles (buyDay, sellDay) y sacando lo mejor de todos. Sin embargo, ¿hay un algoritmo mejor, tal vez uno que se ejecute en O (n) tiempo?

Amo este problema Es una pregunta de entrevista clásica y, dependiendo de cómo piense al respecto, terminará obteniendo mejores y mejores soluciones. Ciertamente es posible hacer esto en un tiempo mejor que O (n 2 ), y he enumerado tres formas diferentes en las que puedes pensar sobre el problema aquí. ¡Espero que esto responda tu pregunta!

Primero, la solución de dividir y vencer. Veamos si podemos resolver esto dividiendo la entrada por la mitad, resolviendo el problema en cada subcampo, y luego combinando los dos juntos. ¡Resulta que realmente podemos hacer esto y podemos hacerlo de manera eficiente! La intuición es la siguiente. Si tenemos un solo día, la mejor opción es comprar ese día y luego volver a venderlo el mismo día sin obtener ganancias. De lo contrario, divida la matriz en dos mitades. Si pensamos cuál podría ser la respuesta óptima, debe estar en uno de tres lugares:

  1. El par correcto de compra / venta ocurre completamente dentro de la primera mitad.
  2. El par correcto de compra / venta ocurre completamente dentro de la segunda mitad.
  3. El par correcto de compra / venta se produce en ambas mitades: compramos en la primera mitad y luego lo vendemos en la segunda mitad.

Podemos obtener los valores para (1) y (2) al invocar recursivamente nuestro algoritmo en la primera y segunda mitades. Para la opción (3), la forma de obtener la mayor ganancia sería comprar en el punto más bajo en la primera mitad y vender en el punto más alto en la segunda mitad. Podemos encontrar los valores mínimo y máximo en las dos mitades simplemente haciendo un escaneo lineal simple sobre la entrada y encontrando los dos valores. Esto nos da un algoritmo con la siguiente recurrencia:

T(1) <= O(1) T(n) <= 2T(n / 2) + O(n) 

Usando el Teorema Maestro para resolver la recurrencia, encontramos que esto se ejecuta en O (n lg n) tiempo y usará O (lg n) espacio para las llamadas recursivas. ¡Acabamos de derrotar a la ingenua solución O (n 2 )!

¡Pero espera! Podemos hacer mucho mejor que esto. Tenga en cuenta que la única razón por la que tenemos un término O (n) en nuestra recurrencia es que tuvimos que escanear toda la entrada tratando de encontrar los valores mínimo y máximo en cada mitad. Dado que ya estamos explorando de forma recursiva cada mitad, ¡quizás podamos hacerlo mejor si la recursión devuelve los valores mínimos y máximos almacenados en cada mitad! En otras palabras, nuestra recursión devuelve tres cosas:

  1. Los tiempos de compra y venta para maximizar los beneficios.
  2. El valor mínimo general en el rango.
  3. El valor máximo general en el rango.

Estos dos últimos valores se pueden calcular recursivamente utilizando una recursión directa que podemos ejecutar al mismo tiempo que la recursión para calcular (1):

  1. Los valores máximo y mínimo de un rango de un solo elemento son solo ese elemento.
  2. Los valores máximo y mínimo de un rango de elementos múltiples se pueden encontrar dividiendo la entrada por la mitad, encontrando los valores máximo y mínimo de cada mitad, y luego tomando sus respectivos máximos y mínimos.

Si usamos este enfoque, nuestra relación de recurrencia es ahora

 T(1) <= O(1) T(n) <= 2T(n / 2) + O(1) 

El uso del Teorema maestro aquí nos da un tiempo de ejecución de O (n) con espacio O (lg n), ¡que es incluso mejor que nuestra solución original!

Pero espere un minuto, ¡podemos hacerlo aún mejor que esto! Pensemos en resolver este problema usando progtwigción dinámica. La idea será pensar sobre el problema de la siguiente manera. Supongamos que conocemos la respuesta al problema después de observar los primeros k elementos. ¿Podríamos usar nuestro conocimiento del elemento st (k + 1), combinado con nuestra solución inicial, para resolver el problema de los primeros elementos (k + 1)? Si es así, podríamos obtener un gran algoritmo resolviendo el problema para el primer elemento, luego los dos primeros, luego los tres primeros, etc. hasta que lo hayamos calculado para los primeros n elementos.

Pensemos en cómo hacer esto. Si solo tenemos un elemento, ya sabemos que tiene que ser el mejor par de compra / venta. Ahora supongamos que conocemos la mejor respuesta para los primeros k elementos y miramos el (k + 1) elemento st. Entonces, la única forma en que este valor puede crear una solución mejor que la que tuvimos para los primeros k elementos es si la diferencia entre el más pequeño de los primeros k elementos y ese nuevo elemento es mayor que la mayor diferencia que hemos calculado hasta ahora. Por lo tanto, supongamos que a medida que avanzamos en los elementos, hacemos un seguimiento de dos valores: el valor mínimo que hemos visto hasta ahora y el máximo beneficio que podemos obtener con solo los primeros k elementos. Inicialmente, el valor mínimo que hemos visto hasta ahora es el primer elemento, y la ganancia máxima es cero. Cuando vemos un nuevo elemento, primero actualizamos nuestras ganancias óptimas calculando cuánto ganaríamos comprando al precio más bajo visto hasta ahora y vendiendo al precio actual. Si esto es mejor que el valor óptimo que hemos calculado hasta el momento, entonces actualizamos la solución óptima para que sea esta nueva ganancia. A continuación, actualizamos el elemento mínimo visto hasta ahora como el mínimo del elemento más pequeño actual y el nuevo elemento.

Ya que en cada paso solo hacemos O (1) trabajo y estamos visitando cada uno de los n elementos exactamente una vez, ¡esto toma O (n) tiempo para completarse! Además, solo usa O (1) almacenamiento auxiliar. ¡Esto es tan bueno como hemos llegado hasta ahora!

Como ejemplo, en sus entradas, así es como podría funcionar este algoritmo. Los números intermedios de cada uno de los valores de la matriz corresponden a los valores mantenidos por el algoritmo en ese punto. En realidad, no almacenarías todo esto (¡tomaría O (n) memoria!), Pero es útil ver evolucionar el algoritmo:

  5 10 4 6 7 min 5 5 4 4 4 best (5,5) (5,10) (5,10) (5,10) (5,10) 

Respuesta: (5, 10)

  5 10 4 6 12 min 5 5 4 4 4 best (5,5) (5,10) (5,10) (5,10) (4,12) 

Respuesta: (4, 12)

  1 2 3 4 5 min 1 1 1 1 1 best (1,1) (1,2) (1,3) (1,4) (1,5) 

Respuesta: (1, 5)

¿Podemos hacerlo mejor ahora? Lamentablemente, no en un sentido asintótico. Si usamos menos de O (n) tiempo, no podemos ver todos los números en grandes entradas y por lo tanto no podemos garantizar que no perderemos la respuesta óptima (podríamos simplemente "esconderla" en los elementos que no miró). Además, no podemos usar menos de O (1) espacio. Puede haber algunas optimizaciones para los factores constantes ocultos en la notación de gran O, pero de lo contrario no podemos esperar encontrar ninguna opción radicalmente mejor.

En general, esto significa que tenemos los siguientes algoritmos:

  • Ingenuo: O (n 2 ) tiempo, O (1) espacio.
  • Dividir y vencer: O (n lg n) tiempo, O (lg n) espacio.
  • Optimizado Divide y Venza: O (n) tiempo, O (lg n) espacio.
  • Progtwigción dinámica: O (n) tiempo, O (1) espacio.

¡Espero que esto ayude!

EDITAR : Si estás interesado, he codificado una versión de Python de estos cuatro algoritmos para que puedas jugar con ellos y juzgar sus actuaciones relativas. Aquí está el código:

 # Four different algorithms for solving the maximum single-sell profit problem, # each of which have different time and space complexity. This is one of my # all-time favorite algorithms questions, since there are so many different # answers that you can arrive at by thinking about the problem in slightly # different ways. # # The maximum single-sell profit problem is defined as follows. You are given # an array of stock prices representing the value of some stock over time. # Assuming that you are allowed to buy the stock exactly once and sell the # stock exactly once, what is the maximum profit you can make? For example, # given the prices # # 2, 7, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5 # # The maximum profit you can make is 8, by buying when the stock price is 1 and # selling when the stock price is 9. Note that while the greatest difference # in the array is 9 (by subtracting 9 - 0), we cannot actually make a profit of # 9 here because the stock price of 0 comes after the stock price of 9 (though # if we wanted to lose a lot of money, buying high and selling low would be a # great idea!) # # In the event that there's no profit to be made at all, we can always buy and # sell on the same date. For example, given these prices (which might # represent a buggy-whip manufacturer:) # # 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 # # The best profit we can make is 0 by buying and selling on the same day. # # Let's begin by writing the simplest and easiest algorithm we know of that # can solve this problem - brute force. We will just consider all O(n^2) pairs # of values, and then pick the one with the highest net profit. There are # exactly n + (n - 1) + (n - 2) + ... + 1 = n(n + 1)/2 different pairs to pick # from, so this algorithm will grow quadratically in the worst-case. However, # it uses only O(1) memory, which is a somewhat attractive feature. Plus, if # our first intuition for the problem gives a quadratic solution, we can be # satisfied that if we don't come up with anything else, we can always have a # polynomial-time solution. def BruteForceSingleSellProfit(arr): # Store the best possible profit we can make; initially this is 0. bestProfit = 0; # Iterate across all pairs and find the best out of all of them. As a # minor optimization, we don't consider any pair consisting of a single # element twice, since we already know that we get profit 0 from this. for i in range(0, len(arr)): for j in range (i + 1, len(arr)): bestProfit = max(bestProfit, arr[j] - arr[i]) return bestProfit # This solution is extremely inelegant, and it seems like there just *has* to # be a better solution. In fact, there are many better solutions, and we'll # see three of them. # # The first insight comes if we try to solve this problem by using a divide- # and-conquer strategy. Let's consider what happens if we split the array into # two (roughly equal) halves. If we do so, then there are three possible # options about where the best buy and sell times are: # # 1. We should buy and sell purely in the left half of the array. # 2. We should buy and sell purely in the right half of the array. # 3. We should buy in the left half of the array and sell in the right half of # the array. # # (Note that we don't need to consider selling in the left half of the array # and buying in the right half of the array, since the buy time must always # come before the sell time) # # If we want to solve this problem recursively, then we can get values for (1) # and (2) by recursively invoking the algorithm on the left and right # subarrays. But what about (3)? Well, if we want to maximize our profit, we # should be buying at the lowest possible cost in the left half of the array # and selling at the highest possible cost in the right half of the array. # This gives a very elegant algorithm for solving this problem: # # If the array has size 0 or size 1, the maximum profit is 0. # Otherwise: # Split the array in half. # Compute the maximum single-sell profit in the left array, call it L. # Compute the maximum single-sell profit in the right array, call it R. # Find the minimum of the first half of the array, call it Min # Find the maximum of the second half of the array, call it Max # Return the maximum of L, R, and Max - Min. # # Let's consider the time and space complexity of this algorithm. Our base # case takes O(1) time, and in our recursive step we make two recursive calls, # one on each half of the array, and then does O(n) work to scan the array # elements to find the minimum and maximum values. This gives the recurrence # # T(1) = O(1) # T(n / 2) = 2T(n / 2) + O(n) # # Using the Master Theorem, this recurrence solves to O(n log n), which is # asymptotically faster than our original approach! However, we do pay a # (slight) cost in memory usage. Because we need to maintain space for all of # the stack frames we use. Since on each recursive call we cut the array size # in half, the maximum number of recursive calls we can make is O(log n), so # this algorithm uses O(n log n) time and O(log n) memory. def DivideAndConquerSingleSellProfit(arr): # Base case: If the array has zero or one elements in it, the maximum # profit is 0. if len(arr) <= 1: return 0; # Cut the array into two roughly equal pieces. left = arr[ : len(arr) / 2] right = arr[len(arr) / 2 : ] # Find the values for buying and selling purely in the left or purely in # the right. leftBest = DivideAndConquerSingleSellProfit(left) rightBest = DivideAndConquerSingleSellProfit(right) # Compute the best profit for buying in the left and selling in the right. crossBest = max(right) - min(left) # Return the best of the three return max(leftBest, rightBest, crossBest) # While the above algorithm for computing the maximum single-sell profit is # better timewise than what we started with (O(n log n) versus O(n^2)), we can # still improve the time performance. In particular, recall our recurrence # relation: # # T(1) = O(1) # T(n) = 2T(n / 2) + O(n) # # Here, the O(n) term in the T(n) case comes from the work being done to find # the maximum and minimum values in the right and left halves of the array, # respectively. If we could find these values faster than what we're doing # right now, we could potentially decrease the function's runtime. # # The key observation here is that we can compute the minimum and maximum # values of an array using a divide-and-conquer approach. Specifically: # # If the array has just one element, it is the minimum and maximum value. # Otherwise: # Split the array in half. # Find the minimum and maximum values from the left and right halves. # Return the minimum and maximum of these two values. # # Notice that our base case does only O(1) work, and our recursive case manages # to do only O(1) work in addition to the recursive calls. This gives us the # recurrence relation # # T(1) = O(1) # T(n) = 2T(n / 2) + O(1) # # Using the Master Theorem, this solves to O(n). # # How can we make use of this result? Well, in our current divide-and-conquer # solution, we split the array in half anyway to find the maximum profit we # could make in the left and right subarrays. Could we have those recursive # calls also hand back the maximum and minimum values of the respective arrays? # If so, we could rewrite our solution as follows: # # If the array has size 1, the maximum profit is zero and the maximum and # minimum values are the single array element. # Otherwise: # Split the array in half. # Compute the maximum single-sell profit in the left array, call it L. # Compute the maximum single-sell profit in the right array, call it R. # Let Min be the minimum value in the left array, which we got from our # first recursive call. # Let Max be the maximum value in the right array, which we got from our # second recursive call. # Return the maximum of L, R, and Max - Min for the maximum single-sell # profit, and the appropriate maximum and minimum values found from # the recursive calls. # # The correctness proof for this algorithm works just as it did before, but now # we never actually do a scan of the array at each step. In fact, we do only # O(1) work at each level. This gives a new recurrence # # T(1) = O(1) # T(n) = 2T(n / 2) + O(1) # # Which solves to O(n). We're now using O(n) time and O(log n) memory, which # is asymptotically faster than before! # # The code for this is given below: def OptimizedDivideAndConquerSingleSellProfit(arr): # If the array is empty, the maximum profit is zero. if len(arr) == 0: return 0 # This recursive helper function implements the above recurrence. It # returns a triple of (max profit, min array value, max array value). For # efficiency reasons, we always reuse the array and specify the bounds as # [lhs, rhs] def Recursion(arr, lhs, rhs): # If the array has just one element, we return that the profit is zero # but the minimum and maximum values are just that array value. if lhs == rhs: return (0, arr[lhs], arr[rhs]) # Recursively compute the values for the first and latter half of the # array. To do this, we need to split the array in half. The line # below accomplishes this in a way that, if ported to other languages, # cannot result in an integer overflow. mid = lhs + (rhs - lhs) / 2 # Perform the recursion. ( leftProfit, leftMin, leftMax) = Recursion(arr, lhs, mid) (rightProfit, rightMin, rightMax) = Recursion(arr, mid + 1, rhs) # Our result is the maximum possible profit, the minimum of the two # minima we've found (since the minimum of these two values gives the # minimum of the overall array), and the maximum of the two maxima. maxProfit = max(leftProfit, rightProfit, rightMax - leftMin) return (maxProfit, min(leftMin, rightMin), max(leftMax, rightMax)) # Using our recursive helper function, compute the resulting value. profit, _, _ = Recursion(arr, 0, len(arr) - 1) return profit # At this point we've traded our O(n^2)-time, O(1)-space solution for an O(n)- # time, O(log n) space solution. But can we do better than this? # # To find a better algorithm, we'll need to switch our line of reasoning. # Rather than using divide-and-conquer, let's see what happens if we use # dynamic programming. In particular, let's think about the following problem. # If we knew the maximum single-sell profit that we could get in just the first # k array elements, could we use this information to determine what the # maximum single-sell profit would be in the first k + 1 array elements? If we # could do this, we could use the following algorithm: # # Find the maximum single-sell profit to be made in the first 1 elements. # For i = 2 to n: # Compute the maximum single-sell profit using the first i elements. # # How might we do this? One intuition is as follows. Suppose that we know the # maximum single-sell profit of the first k elements. If we look at k + 1 # elements, then either the maximum profit we could make by buying and selling # within the first k elements (in which case nothing changes), or we're # supposed to sell at the (k + 1)st price. If we wanted to sell at this price # for a maximum profit, then we would want to do so by buying at the lowest of # the first k + 1 prices, then selling at the (k + 1)st price. # # To accomplish this, suppose that we keep track of the minimum value in the # first k elements, along with the maximum profit we could make in the first # k elements. Upon seeing the (k + 1)st element, we update what the current # minimum value is, then update what the maximum profit we can make is by # seeing whether the difference between the (k + 1)st element and the new # minimum value is. Note that it doesn't matter what order we do this in; if # the (k + 1)st element is the smallest element so far, there's no possible way # that we could increase our profit by selling at that point. # # To finish up this algorithm, we should note that given just the first price, # the maximum possible profit is 0. # # This gives the following simple and elegant algorithm for the maximum single- # sell profit problem: # # Let profit = 0. # Let min = arr[0] # For k = 1 to length(arr): # If arr[k] < min, set min = arr[k] # If profit < arr[k] - min, set profit = arr[k] - min # # This is short, sweet, and uses only O(n) time and O(1) memory. The beauty of # this solution is that we are quite naturally led there by thinking about how # to update our answer to the problem in response to seeing some new element. # In fact, we could consider implementing this algorithm as a streaming # algorithm, where at each point in time we maintain the maximum possible # profit and then update our answer every time new data becomes available. # # The final version of this algorithm is shown here: def DynamicProgrammingSingleSellProfit(arr): # If the array is empty, we cannot make a profit. if len(arr) == 0: return 0 # Otherwise, keep track of the best possible profit and the lowest value # seen so far. profit = 0 cheapest = arr[0] # Iterate across the array, updating our answer as we go according to the # above pseudocode. for i in range(1, len(arr)): # Update the minimum value to be the lower of the existing minimum and # the new minimum. cheapest = min(cheapest, arr[i]) # Update the maximum profit to be the larger of the old profit and the # profit made by buying at the lowest value and selling at the current # price. profit = max(profit, arr[i] - cheapest) return profit # To summarize our algorithms, we have seen # # Naive: O(n ^ 2) time, O(1) space # Divide-and-conquer: O(n log n) time, O(log n) space # Optimized divide-and-conquer: O(n) time, O(log n) space # Dynamic programming: O(n) time, O(1) space 

Este es el problema de sum de sum máxima con un poco de indirección. El problema de la sum de sum máxima se da una lista de enteros que pueden ser positivos o negativos, encontrar la sum más grande de un subconjunto contiguo de esa lista.

Puede convertir trivialmente este problema a ese problema tomando el beneficio o la pérdida entre días consecutivos. Entonces, transformaría una lista de precios de acciones, por ejemplo [5, 6, 7, 4, 2] en una lista de ganancias / pérdidas, por ejemplo, [1, 1, -3, -2] . El problema de la sum subsecuencia es entonces bastante fácil de resolver: Encuentre la subsecuencia con la sum más grande de elementos en una matriz

No estoy seguro de por qué esto se considera una pregunta de progtwigción dinámica. He visto esta pregunta en libros de texto y guías de algoritmo que usan tiempo de ejecución O (n log n) y O (log n) para espacio (por ejemplo, Elementos de entrevistas de progtwigción). Parece un problema mucho más simple de lo que las personas creen.

Esto funciona mediante el seguimiento del beneficio máximo, el precio mínimo de compra y, en consecuencia, el precio de compra / venta óptimo. A medida que atraviesa cada elemento de la matriz, comprueba si el elemento dado es más pequeño que el precio mínimo de compra. Si es así, el índice mínimo de precio de compra ( min ) se actualiza para que sea el índice de ese elemento. Además, para cada elemento, el algoritmo becomeABillionair verifica si arr[i] - arr[min] (la diferencia entre el elemento actual y el precio mínimo de compra) es mayor que la ganancia actual. Si es así, la ganancia se actualiza a esa diferencia y la compra se establece en arr[min] y la venta se establece en arr[i] .

Se ejecuta en un solo pase.

 static void becomeABillionair(int arr[]) { int i = 0, buy = 0, sell = 0, min = 0, profit = 0; for (i = 0; i < arr.length; i++) { if (arr[i] < arr[min]) min = i; else if (arr[i] - arr[min] > profit) { buy = min; sell = i; profit = arr[i] - arr[min]; } } System.out.println("We will buy at : " + arr[buy] + " sell at " + arr[sell] + " and become billionairs worth " + profit ); } 

Coautor: https://stackoverflow.com/users/599402/ephraim

aquí está mi solución Java:

 public static void main(String[] args) { int A[] = {5,10,4,6,12}; int min = A[0]; // Lets assume first element is minimum int maxProfit = 0; // 0 profit, if we buy & sell on same day. int profit = 0; int minIndex = 0; // Index of buy date int maxIndex = 0; // Index of sell date //Run the loop from next element for (int i = 1; i < A.length; i++) { //Keep track of minimum buy price & index if (A[i] < min) { min = A[i]; minIndex = i; } profit = A[i] - min; //If new profit is more than previous profit, keep it and update the max index if (profit > maxProfit) { maxProfit = profit; maxIndex = i; } } System.out.println("maxProfit is "+maxProfit); System.out.println("minIndex is "+minIndex); System.out.println("maxIndex is "+maxIndex); } 

El problema es idéntico a la subsecuencia máxima
Lo resolví usando progtwigción dinámica. Mantenga un registro de las fechas actual y anterior (Ganancia, compra y venta) Si la stream es mayor que la anterior, reemplace la anterior por la actual.

  int prices[] = { 38, 37, 35, 31, 20, 24, 35, 21, 24, 21, 23, 20, 23, 25, 27 }; int buyDate = 0, tempbuyDate = 0; int sellDate = 0, tempsellDate = 0; int profit = 0, tempProfit =0; int i ,x = prices.length; int previousDayPrice = prices[0], currentDayprice=0; for(i=1 ; i previousDayPrice ) { // price went up tempProfit = tempProfit + currentDayprice - previousDayPrice; tempsellDate = i; } else { // price went down if(tempProfit>profit) { // check if the current Profit is higher than previous profit.... profit = tempProfit; sellDate = tempsellDate; buyDate = tempbuyDate; } // re-intialized buy&sell date, profit.... tempsellDate = i; tempbuyDate = i; tempProfit =0; } previousDayPrice = currentDayprice; } // if the profit is highest till the last date.... if(tempProfit>profit) { System.out.println("buydate " + tempbuyDate + " selldate " + tempsellDate + " profit " + tempProfit ); } else { System.out.println("buydate " + buyDate + " selldate " + sellDate + " profit " + profit ); } 

He encontrado una solución simple: el código es más explicativo. Es una de esas preguntas de progtwigción dinámica.

El código no se ocupa de la comprobación de errores ni de los casos extremos. Es solo una muestra para dar la idea de la lógica básica para resolver el problema.

 namespace MaxProfitForSharePrice { class MaxProfitForSharePrice { private static int findMax(int a, int b) { return a > b ? a : b; } private static void GetMaxProfit(int[] sharePrices) { int minSharePrice = sharePrices[0], maxSharePrice = 0, MaxProft = 0; int shareBuyValue = sharePrices[0], shareSellValue = sharePrices[0]; for (int i = 0; i < sharePrices.Length; i++) { if (sharePrices[i] < minSharePrice ) { minSharePrice = sharePrices[i]; // if we update the min value of share, we need to reset the Max value as // we can only do this transaction in-sequence. We need to buy first and then only we can sell. maxSharePrice = 0; } else { maxSharePrice = sharePrices[i]; } // We are checking if max and min share value of stock are going to // give us better profit compare to the previously stored one, then store those share values. if (MaxProft < (maxSharePrice - minSharePrice)) { shareBuyValue = minSharePrice; shareSellValue = maxSharePrice; } MaxProft = findMax(MaxProft, maxSharePrice - minSharePrice); } Console.WriteLine("Buy stock at ${0} and sell at ${1}, maximum profit can be earned ${2}.", shareBuyValue, shareSellValue, MaxProft); } static void Main(string[] args) { int[] sampleArray = new int[] { 1, 3, 4, 1, 1, 2, 11 }; GetMaxProfit(sampleArray); Console.ReadLine(); } } } 
 public static double maxProfit(double [] stockPrices) { double initIndex = 0, finalIndex = 0; double tempProfit = list[1] - list[0]; double maxSum = tempProfit; double maxEndPoint = tempProfit; for(int i = 1 ;i 

Aquí está mi solución. modifica el algoritmo de sub-secuencia máxima. Resuelve el problema en O (n). Creo que no se puede hacer más rápido.

Este es un problema interesante, porque parece difícil, pero una reflexión cuidadosa produce una solución elegante y reducida.

Como se ha notado, se puede resolver la fuerza bruta en el tiempo O (N ^ 2). Para cada entrada en la matriz (o lista), itere sobre todas las entradas previas para obtener el mínimo o máximo dependiendo de si el problema es encontrar la mayor ganancia o pérdida.

A continuación se explica cómo pensar en una solución en O (N): cada entrada representa un nuevo máximo posible (o min). Entonces, todo lo que tenemos que hacer es guardar el mínimo anterior (o máximo), y comparar el diff con el mínimo actual (y máximo). Pan comido.

Aquí está el código, en Java como una prueba JUnit:

 import org.junit.Test; public class MaxDiffOverSeriesProblem { @Test public void test1() { int[] testArr = new int[]{100, 80, 70, 65, 95, 120, 150, 75, 95, 100, 110, 120, 90, 80, 85, 90}; System.out.println("maxLoss: " + calculateMaxLossOverSeries(testArr) + ", maxGain: " + calculateMaxGainOverSeries(testArr)); } private int calculateMaxLossOverSeries(int[] arr) { int maxLoss = 0; int idxMax = 0; for (int i = 0; i < arr.length; i++) { if (arr[i] > arr[idxMax]) { idxMax = i; } if (arr[idxMax] - arr[i] > maxLoss) { maxLoss = arr[idxMax] - arr[i]; } } return maxLoss; } private int calculateMaxGainOverSeries(int[] arr) { int maxGain = 0; int idxMin = 0; for (int i = 0; i < arr.length; i++) { if (arr[i] < arr[idxMin]) { idxMin = i; } if (arr[i] - arr[idxMin] > maxGain) { maxGain = arr[i] - arr[idxMin]; } } return maxGain; } } 

En el caso de calcular la mayor pérdida, hacemos un seguimiento del máximo en la lista (precio de compra) hasta la entrada actual. Luego calculamos la diferencia entre la entrada máxima y la actual. Si max – current> maxLoss, entonces mantenemos esta diferencia como el nuevo maxLoss. Dado que se garantiza que el índice de max es menor que el índice de stream, garantizamos que la fecha de ‘compra’ es menor que la fecha de ‘venta’.

En el caso de calcular la mayor ganancia, todo se revierte. Hacemos un seguimiento de los minutos en la lista hasta la entrada actual. Calculamos la diferencia entre la entrada mínima y la actual (invirtiendo el orden en la resta). Si current – min> maxGain, entonces mantenemos esta diferencia como la nueva maxGain. Nuevamente, el índice de ‘comprar’ (min) viene antes del índice de stream (‘vender’).

Solo necesitamos hacer un seguimiento de maxGain (o maxLoss), y el índice de mínimo o máximo, pero no ambos, y no necesitamos comparar índices para validar que ‘comprar’ es menor que ‘vender’, ya que obtener esto naturalmente

Máxima ganancia única de venta, solución O (n)

 function stocks_n(price_list){ var maxDif=0, min=price_list[0] for (var i in price_list){ p = price_list[i]; if (pmaxDif) maxDif=p-min; } return maxDif } 

Aquí hay un proyecto que hace pruebas de complejidad de tiempo en enfoques o (N) vs o (n ^ 2) en un conjunto de datos aleatorios en 100k ints. O (n ^ 2) toma 2 segundos, mientras que O (n) toma 0.01s

https://github.com/gulakov/complexity.js

 function stocks_n2(ps){ for (maxDif=0,i=_i=0;p=ps[i++];i=_i++) for (;p2=ps[i++];) if (p2-p>maxDif) maxDif=p2-p return maxDif } 

This is the slower, o(n^2) approach that loops thru the rest of the days for each day, double loop.

 static void findmaxprofit(int[] stockvalues){ int buy=0,sell=0,buyingpoint=0,sellingpoint=0,profit=0,currentprofit=0; int finalbuy=0,finalsell=0; if(stockvalues.length!=0){ buy=stockvalues[0]; } for(int i=1;ibuy){ sell=stockvalues[i]; sellingpoint=i; } currentprofit=sell-buy; if(profitbuyingpoint){ finalbuy=buy; finalsell=sell; profit=currentprofit; } } if(profit>0) System.out.println("Buy shares at "+finalbuy+" INR and Sell Shares "+finalsell+" INR and Profit of "+profit+" INR"); else System.out.println("Don't do Share transacations today"); } 

A possibility to determine the maximum profit might be to keep track of the left-side minimum and right-side maximum elements in the array at each index in the array. When you are then iterating through the stock prices, for any given day you will know the lowest price up to that day, and you will also know the maximum price after (and including) that day.

For instance, let’s define a min_arr and max_arr , with the given array being arr . Index i in min_arr would be the minimum element in arr for all indices <= i (left of and including i). Index i in max_arr would be the maximum element in arr for all indices >= i (right of and including i). Then, you could find the maximum difference between the corresponding elements in max_arr and `min_arr':

 def max_profit(arr) min_arr = [] min_el = arr.first arr.each do |el| if el < min_el min_el = el min_arr << min_el else min_arr << min_el end end max_arr = [] max_el = arr.last arr.reverse.each do |el| if el > max_el max_el = el max_arr.unshift(max_el) else max_arr.unshift(max_el) end end max_difference = max_arr.first - min_arr.first 1.upto(arr.length-1) do |i| max_difference = max_arr[i] - min_arr[i] if max_difference < max_arr[i] - min_arr[i] end return max_difference end 

This should run in O(n) time, but I believe it uses up a lot of space.

Here’s my solution

public static int maxProfit(ArrayList in){

  int min = in.get(0), max = 0; for(int i=0; i 

}

This is maximum difference between two elements in array and this is my solution:

O(N) time complexity O(1) space complexity

  int[] arr = {5, 4, 6 ,7 ,6 ,3 ,2, 5}; int start = 0; int end = 0; int max = 0; for(int i=1; i0){ if((arr[i] -arr[start])>=currMax && ((arr[i] -arr[start])>=(arr[end] -arr[start]))){ end = i; } else if(currMax>(arr[i] -arr[start]) && currMax >(arr[end] - arr[start])){ start = i-1; end = i; } } } max = arr[end] - arr[start]; System.out.println("max: "+max+" start: "+start+" end: "+end); 

For all the answers keeping track of the minimum and maximum elements, that solution is actually an O(n^2) solution. This is because at the end it must be checked whether the maximum occurred after the minimum or not. In case it didn’t, further iterations are required until that condition is met, and this leaves a worst-case of O(n^2). And if you want to skip the extra iterations then a lot more space is required. Either way, a no-no as compared to the dynamic programming solution

After failing this in a live coding exam for a FB solutions engineer position I had to solve it in a calm cool atmosphere, so here are my 2 cents:

 var max_profit = 0; var stockPrices = [23,40,21,67,1,50,22,38,2,62]; var currentBestBuy = 0; var currentBestSell = 0; var min = 0; for(var i = 0;i < (stockPrices.length - 1) ; i++){ if(( stockPrices[i + 1] - stockPrices[currentBestBuy] > max_profit) ){ max_profit = stockPrices[i + 1] - stockPrices[currentBestBuy]; currentBestSell = i + 1; } if(stockPrices[i] < stockPrices[currentBestBuy]){ min = i; } if( max_profit < stockPrices[i + 1] - stockPrices[min] ){ max_profit = stockPrices[i + 1] - stockPrices[min]; currentBestSell = i + 1; currentBestBuy = min; } } console.log(currentBestBuy); console.log(currentBestSell); console.log(max_profit); 

The only answer really answering the question is the one of @akash_magoon (and in such a simple way!), but it does not return the exact object specified in the question. I refactored a bit and have my answer in PHP returning just what is asked:

 function maximizeProfit(array $dailyPrices) { $buyDay = $sellDay = $cheaperDay = $profit = 0; for ($today = 0; $today < count($dailyPrices); $today++) { if ($dailyPrices[$today] < $dailyPrices[$cheaperDay]) { $cheaperDay = $today; } elseif ($dailyPrices[$today] - $dailyPrices[$cheaperDay] > $profit) { $buyDay = $cheaperDay; $sellDay = $today; $profit = $dailyPrices[$today] - $dailyPrices[$cheaperDay]; } } return [$buyDay, $sellDay]; } 

A neat solution :

 + (int)maxProfit:(NSArray *)prices { int maxProfit = 0; int bestBuy = 0; int bestSell = 0; int currentBestBuy = 0; for (int i= 1; i < prices.count; i++) { int todayPrice = [prices[i] intValue]; int bestBuyPrice = [prices[currentBestBuy] intValue]; if (todayPrice < bestBuyPrice) { currentBestBuy = i; bestBuyPrice = todayPrice; } if (maxProfit < (todayPrice - bestBuyPrice)) { bestSell = i; bestBuy = currentBestBuy; maxProfit = (todayPrice - bestBuyPrice); } } NSLog(@"Buy Day : %d", bestBuy); NSLog(@"Sell Day : %d", bestSell); return maxProfit; } 

The top voted answer does not allow for cases in which the maximum profit is negative and should be modified to allow for such cases. One can do so by limiting the range of the loop to (len(a) – 1) and changing the way profit is determined by shifting the index by one.

 def singSellProfit(a): profit = -max(a) low = a[0] for i in range(len(a) - 1): low = min(low, a[i]) profit = max(profit, a[i + 1] - low) return profit 

Compare this version of the function with the previous for the array:

 s = [19,11,10,8,5,2] singSellProfit(s) -1 DynamicProgrammingSingleSellProfit(s) 0 
 def get_max_profit(stock): p=stock[0] max_profit=0 maxp=p minp=p for i in range(1,len(stock)): p=min(p,stock[i]) profit=stock[i]-p if profit>max_profit: maxp=stock[i] minp=p max_profit=profit return minp,maxp,max_profit stock_prices = [310,315,275,295,260,270,290,230,255,250] print(get_max_profit(stock_prices)) 

This program in python3 can return the buying price and selling price that will maximize the profit, computed with Time complexity of O(n) and Space complexity of O(1) .