这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战
圆圈中最后剩下的数字
剑指Offer 62. 圆圈中最后剩下的数字
难度:简单
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. 股票的最大利润
难度:中等
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例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)
坚持每日一练!前端小萌新一枚,希望能点个赞
哇~