面试题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
解题思路:约瑟夫问题
递推公式:让f[i]为i个人玩游戏报m退出最后的胜利者的编号,最后的结果自然是f[n]
f[1] = 0;
f[i] = (f[i - 1] + m) mod i;
因为递推,所以可以不用保存状态;
class Solution {
public:
int LastRemaining_Solution(unsigned int n, unsigned int m)
{
if(n <= 0 && m <= 0) return -1;
int t = 0;
for(int i = 2; i <= n; i++)
t = (t + m) % i;
return t;
}
};
面试题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。
解题思路:
(1)把数组每个数减去前面的一个数,转化成一个差值数组,比如[7, 1, 5, 3, 6, 4]变成
[7,-6,4,-2,3,-2]。这样问题就转化成了:求一个数组区间,区间内所有数加起来最大。因为
6 - 1 = (6-3)+(3-5) + (5-1)。
(2)使用“大问题转化成小问题”的思路: 一个n长的数组的解如何跟n-1长数组的解联系起来?
如果在这两者之间建立联系,就可以把n长的一直转化成1长的问题,问题就直接解决了。
using namespace std;
int main() {
system("pause");
return 0;
}
//
int MaxDiff(const int *numbers, unsigned length) {
if (numbers == NULL || length < 2)return 0;
int min = numbers[0];
int resu = numbers[1] - min;
for (int i = 2; i != length; i++) {
//检查前一天的值是不是最小值,是就更新最小值
if (numbers[i-1] < min) {
min = numbers[i-1];
}
//当前时间卖出能赚到最多的钱吗
if ((numbers[i] - min) > resu) {
resu = numbers[i] - min;
}
}
return resu;
};