375.猜数字大小II

题目

我们正在玩一个猜数游戏,游戏规则如下:

我从 **1 **到 n 之间选择一个数字,你来猜我选了哪个数字。

每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了。

然而,当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。直到你猜到我选的数字,你才算赢得了这个游戏。

示例:

n = 10, 我选择了8.

第一轮: 你猜我选择的数字是5,我会告诉你,我的数字更大一些,然后你需要支付5块。
第二轮: 你猜是7,我告诉你,我的数字更大一些,你支付7块。
第三轮: 你猜是9,我告诉你,我的数字更小一些,你支付9块。

游戏结束。8 就是我选的数字。

你最终要支付 5 + 7 + 9 = 21 块钱。

给定 n ≥ 1,计算你至少需要拥有多少现金才能确保你能赢得这个游戏

思路

刚开始没看明白,看了解析才知道。
设置数组dp,其中dp[i][j]表示从i到j所需拥有多仨后现金才能保证赢得这个游戏。
因此最后返回dp[1][n]即可。

对于dp[i][j],其值应该为:每次猜测结果为x的时候,dp[i][x-1]与dp[x+1][j]中的最大值与猜测的x相加,这样才能保证但在dp[i][j]内所有的猜测组合都可以在某个现金之内完成。
从n->0开始遍历i,对于每个i,从i-n遍历j,对于里面的所有j,选择预测为x的时候,选择dp[i][x-1]与dp[x+1][j]中的最大值与其相加相加即可。
对于

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int getMoneyAmount(int n) {
int dp[n+2][n+2];
memset(dp,0,sizeof(int)*(n+2)*(n+2));
for(int i=n;i>=1;--i){
for(int j = i;j <= n;++j){
if(i==j) dp[i][j] = 0;
else{
dp[i][j] = INT_MAX;
for(int x=i;x<=j;++x){
dp[i][j] = min(dp[i][j],max(dp[i][x-1],dp[x+1][j])+x);
}
}
}
}
return dp[1][n];
}
};

502.IPO

题目

假设 力扣(LeetCode)即将开始 IPO 。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后得到最大总资本的方式。

给你 n 个项目。对于每个项目 i ,它都有一个纯利润 profits[i] ,和启动该项目需要的最小资本 capital[i]

最初,你的资本为 w 。当你完成一个项目时,你将获得纯利润,且利润将被添加到你的总资本中。

总而言之,从给定项目中选择 最多 k 个不同项目的列表,以 最大化最终资本 ,并输出最终可获得的最多资本。

答案保证在 32 位有符号整数范围内。

示例 1:

输入:k = 2, w = 0, profits = [1,2,3], capital = [0,1,1]
输出:4
解释: 由于你的初始资本为 0,你仅可以从 0 号项目开始。
在完成后,你将获得 1 的利润,你的总资本将变为 1。
此时你可以选择开始 1 号或 2 号项目。
由于你最多可以选择两个项目,所以你需要完成 2 号项目以获得最大的资本。
因此,输出最后最大化的资本,为 0 + 1 + 3 = 4。

示例 2:

输入:k = 3, w = 0, profits = [1,2,3], capital = [0,1,2]
输出:6

提示:

  • 1 <= k <= 105
  • 0 <= w <= 109
  • n == profits.length
  • n == capital.length
  • 1 <= n <= 105
  • 0 <= profits[i] <= 104
  • 0 <= capital[i] <= 109

    思路

  • 银行家算法*
    将capital和profits配对,并按照captial从小到大进行排序。
    每次对比w和capitali,如果w比capitali大,则将对应的profitsi加入到优先队列中。
    全部加完后,从优先队列中选择最大的profits加到w中。
    重复上述k次。

    代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Solution {
    public:
    int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {
    int n = profits.size();
    vector<pair<int,int>> arr(n);
    priority_queue<int,vector<int>,less<int>> pq;
    for(int i=0;i<n;++i){ arr[i] = {capital[i],profits[i]}; }
    int idx = 0;
    sort(arr.begin(),arr.end());
    for(int i=0;i<k;++i){
    while(idx<n&&arr[idx].first<=w){
    pq.push(arr[idx++].second);
    }
    if(!pq.empty()){
    w+=pq.top();
    pq.pop();
    }else{
    break;
    }
    }
    return w;
    }
    }

927-三等分

题目

927. 三等分

难度困难 51

给定一个由 01 组成的数组 A,将数组分成 3 个非空的部分,使得所有这些部分表示相同的二进制值。

如果可以做到,请返回任何 [i, j],其中 i+1 < j,这样一来:

  • A[0], A[1], ..., A[i] 组成第一部分;
  • A[i+1], A[i+2], ..., A[j-1] 作为第二部分;
  • A[j], A[j+1], ..., A[A.length - 1] 是第三部分。
  • 这三个部分所表示的二进制值相等。

如果无法做到,就返回 [-1, -1]

注意,在考虑每个部分所表示的二进制时,应当将其看作一个整体。例如,[1,1,0] 表示十进制中的 6,而不会是 3。此外,前导零也是被允许的,所以 [0,1,1][1,1] 表示相同的值。

示例 1:

输入:[1,0,1,0,1]
输出:[0,3]

示例 2:

输出:[1,1,0,1,1]
输出:[-1,-1]

提示:

  1. 3 <= A.length <= 30000
  2. A[i] == 0A[i] == 1

思路

每组1的数目肯定相等。于是先统计1的位置并保存为bit,之后看bit的长度是否大于3、是否能被3整除。

能被3整除的情况下,分成三分,每份为t。每一份中1肯定都是t个,前缀0可以忽略,因此应该看后缀0有多少。前两份的前缀0和后面的后缀0混合在一起,可以自由组合,因此先不看。只看第3份的后缀0。如果第3份的后缀0个数比前两份之间的都多,也是不行的。在第三分的后缀0个数小于1、2和2、3之间的0的个数的时候,分别从第1份最后一个1后面延伸相应个数的0、第2份最后一个1后面延伸相应个数的0,返回位置即为答案。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
vector<int> threeEqualParts(vector<int>& arr) {
vector<int> bit;
int len = arr.size();
for(int i=0;i<arr.size();i++)
if(arr[i]==1)
bit.push_back(i);
if(bit.size()%3) return {-1,-1};
if(bit.empty()) return {0,2};
int t = bit.size()/3;
int back_zero = len - 1 - bit.back();
if(back_zero>bit[2*t]-bit[2*t-1]-1||back_zero>bit[t]-bit[t-1]-1)
return {-1,-1};
vector<int> first(bit.begin(),bit.begin()+t);
vector<int> second(bit.begin()+t,bit.begin()+2*t);
vector<int> third(bit.begin()+2*t,bit.end());
for(int i=t-1;i>0;--i){
if(first[i]-first[i-1]!=second[i]-second[i-1]||
first[i]-first[i-1]!=third[i]-third[i-1])
return {-1,-1};
}
int i = bit[t-1]+back_zero;
int j = bit[2*t-1]+back_zero+1;
return {i,j};
}
};