昨晚临时做了下美团2017年的校招题(纯属无聊),感觉美团的题就做得很舒服了,考想法,代码量小,只要你的idea够好,代码就几行,学习了!
题目链接:[点这里].
大富翁游戏,玩家根据骰子的点数决定走的步数,即骰子点数为1时可以走一步,点数为2时可以走两步,点数为n时可以走n步。求玩家走到第n步(n<=骰子最大点数且是方法的唯一入参)时,总共有多少种投骰子的方法。
n很小,所以你直接算到6就好了,我一开始就没多想,直接记忆化搜了下.这个题和走楼梯那个题想法是一样的.
#include
using namespace std;
int dp[7];
int dfs(int n)
{
if (n == 1)
return dp[1] = 1;
if (dp[n])
return dp[n];
int ret = 1;
for (int i = 1; i < n; i++)
ret += dfs(i);
return dp[n] = ret;
}
int main()
{
dfs(6);
int n;
while (cin >> n)
cout << dp[n] << endl;
return 0;
}
其实这个题有更简单的方法,就是推通项公式.
dp[n]=dp[n−1]+dp[n−2]+⋯+dp[1] ;
dp[n−1]=dp[n−2]+⋯+dp[1] ;
两个等式相减,得到: dp[n]=dp[n−1]∗2,dp[1]=1 ,即 dp[n]=2n−1 ,所以下面的代码更好.
#include
using namespace std;
int main()
{
int n;
while (cin >> n)
cout << pow(2, n - 1) << endl;
return 0;
}
给你六种面额 1、5、10、20、50、100 元的纸币,假设每种币值的数量都足够多,编写程序求组成N元(N为0~10000的非负整数)的不同组合的个数。
首先我想到的是动态规划,类似于整数拆分, dp[i][j] 表示,面值为i的钱拿出 value[j] 块钱有多少种方案,那么为了避免重复, dp[i][j] 可以由 ∑jk=0dp[i−value[j]][k] 转移过来,初始化的时候 dp[value[i]][i]=1 ,最后面值为 n 的方案数为 ∑6i=0dp[n][i] 。
#include
using namespace std;
#define MAX_N 10001
#define MAX_Z 6
typedef long long LL;
int value[] = {1, 5, 10, 20, 50, 100};
int main()
{
vector<vector > dp(MAX_N, vector (MAX_Z, 0));
for (int i = 0; i < MAX_Z; i++)
dp[value[i]][i] = 1;
vector sum(MAX_N, 0);
for (int i = 1; i < MAX_N; i++) {
for (int j = MAX_Z - 1; j >= 0; j--) {
if (i - value[j] <= 0)
continue;
for (int k = j; k >= 0; k--) {
dp[i][j] += dp[i - value[j]][k];
}
}
}
for (int i = 1; i < MAX_N; i++)
for (int j = 0; j < MAX_Z; j++)
sum[i] += dp[i][j];
int n;
while (cin >> n)
cout << sum[n] << endl;
return 0;
}
仔细想想,这其实是一个完全背包问题嘛,先用面值为1的钱去填充,然后再用面值为5的钱去填充,这个时候得到的方案就是面值1和面值5的钱一起去填充的方案数,依次类推就可以了,可以看到完全背包问题可以转化为01背包问题,而且可以优化降维,确实很不错的解法。
#include
using namespace std;
#define MAX_N 10001
#define MAX_Z 6
typedef long long LL;
int value[] = {1, 5, 10, 20, 50, 100};
int main()
{
vector dp(MAX_N, 0);
dp[0] = 1;
for (int i = 0; i < MAX_Z; i++)
for (int j = value[i]; j < MAX_N; j++)
dp[j] += dp[j - value[i]];
int n;
while (cin >> n)
cout << dp[n] << endl;
return 0;
}
给定一组非负整数组成的数组h,代表一组柱状图的高度,其中每个柱子的宽度都为1。 在这组柱状图中找到能组成的最大矩形的面积(如图所示)。 入参h为一个整型数组,代表每个柱子的高度,返回面积的值。
单调栈的裸题,这里就不多讲述了,百度搜单调栈基本都会出现这个题。
#include
using namespace std;
typedef long long LL;
struct Node{
LL id;
LL value;
Node() {}
Node(LL id, LL value) : id(id), value(value) {}
};
int main()
{
int n;
while (~scanf("%d", &n)) {
stack st;
LL ans = 0;
for (int i = 0; i < n; i++) {
LL x;
scanf("%lld", &x);
LL pre = i;
while (!st.empty() && st.top().value > x)
ans = max(ans, (i - (pre = st.top().id)) * st.top().value), st.pop();
st.emplace(pre, x);
}
while (!st.empty()) {
ans = max(ans, (n - st.top().id) * st.top().value);
st.pop();
}
printf("%lld\n", ans);
}
return 0;
}
给出两个字符串(可能包含空格),找出其中最长的公共连续子串,输出其长度。
还是动态规划,类似最长公共子串,不过当
str[i] != str[j]
时,dp[i][j]=0
,这是因为再往后即使有相同的字母也不是连续的了,要注意是连续的,忘记说了, dp[i][j] 表示字符串str1.substr(0,i),str2.(0,j)
最长连续公共子串的长度,连续子串的结尾分别是i,j
。
#include
using namespace std;
typedef long long LL;
int main()
{
string str1, str2;
while (getline(cin, str1)) {
getline(cin, str2);
vector<vector<int> > dp(str1.size() + 1, vector<int>(str2.size() + 1, 0));
int ans = 0;
for (int i = 1; i <= str1.size(); i++)
for (int j = 1; j <= str2.size(); j++)
dp[i][j] = str1[i - 1] == str2[j - 1] ? dp[i - 1][j - 1] + 1 : 0,
ans = max(ans, dp[i][j]);
cout << ans << endl;
}
return 0;
}