JS算法之动态规划

285 阅读2分钟

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

圆圈中最后剩下的数字

剑指Offer 62. 圆圈中最后剩下的数字

难度:简单

题目:leetcode-cn.com/problems/yu…

0,1,...,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例1:

 输入: n = 5, m = 3
 输出: 3

示例2:

 输入: n = 10, m = 17
 输出: 2

限制:

  • 1 <= n <= 10^5
  • 1 <= m <= 10^6

题解

动态规划

本质上这道题就是一个约瑟夫环。n个人编号0~n-1,每数m次删掉一个人。使用f(n)表示n个人最终剩下人的编号。

n个人删掉的第一个人的编号是(m-1)%n,其之后的人编号为(m-1+1)%n即m%n是下一个约瑟夫环的编号为0的那个人,n-1个人时编号为i的人就是n个人(m+i)%n。

因此得出f(n)=(m+f(n-1))%n,1个人时只有一个编号0,f(1)=0。

因此动态规划转移方程为:

代码如下:

 /**
  * @param {number} n
  * @param {number} m
  * @return {number}
  */
 ​
 var lastRemaining = function (n, m) {
   let ans = 0;
   for (let i = 2; i <= n; i++) {
     ans = (ans + m) % i;
   }
   return ans;
 };
  • 时间复杂度:O(N)
  • 空间复杂度:O(1)

股票的最大利润

剑指Offer 63. 股票的最大利润

难度:中等

题目:leetcode-cn.com/problems/gu…

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

示例1:

 输入: [7,1,5,3,6,4]
 输出: 5
 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
      注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例2:

 输入: [7,6,4,3,1]
 输出: 0
 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

限制:0 <= 数组长度 <= 10^5

题解

法一 暴力法

两层for循环,直接暴力出最大利润。

 /**
  * @param {number[]} prices
  * @return {number}
  */
 var maxProfit = function (prices) {
   let res = 0;
   for (let i = 0; i < prices.length; i++) {
     for (let j = i + 1; j < prices.length; j++) {
       res = Math.max(res, prices[j] - prices[i])
     }
   }
   return res;
 };
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)

法二 动态规划

状态定义:设dp[i]为以prices[i]为结尾的子数组的最大利润(即前i日的最大利润)。

转移方程:前i日最大利润dp[i]为前一天的最大利润dp[i-1]和第i天卖出利润prices[i]-min(prices[0:i])的最大值,状态方程如下:

因为这里的dp[i]只与dp[i-1]有关,这里的dp其实可以用一个变量去取代。

 var maxProfit = function (prices) {
   let dp = 0,cost = Infinity;
   for(let i = 0; i < prices.length; i++){
     cost = Math.min(cost,prices[i]);
     dp = Math.max(dp,prices[i] - cost);
   }
   return dp;
 };
  • 时间复杂度:O(N)
  • 空间复杂度:O(1)

坚持每日一练!前端小萌新一枚,希望能点个哇~