牛客刷题——美团2017秋招编程


题目链接

第一题 大富翁

题目

大富翁游戏,玩家根据骰子的点数决定走的步数,即骰子点数为1时可以走一步,点数为2时可以走两步,点数为n时可以走n步。求玩家走到第n步(n<=骰子最大点数且是方法的唯一入参)时,总共有多少种投骰子的方法。

输入样例

6

输出样例

32

参考思路及答案
做完题后,看别人的答案,才发觉自己好愚蠢,没有发现答案就是 2 n − 1 2^{n-1} 2n1
递归: f ( n ) = f ( n − 1 ) + f ( n − 2 ) + . . . + f ( 1 ) + 1 f(n) = f(n-1)+f(n-2)+...+f(1)+1 f(n)=f(n1)+f(n2)+...+f(1)+1 f ( 1 ) = 1 f(1) = 1 f(1)=1 f ( n ) = 2 n − 1 f(n) = 2^{n-1} f(n)=2n1

#include<iostream>
#include<algorithm>
using namespace std; 
int main(){
	int n;
	while(cin>>n){
		cout<<pow(2,n-1)<<endl;
	}
	return 0;
}

我的想法(挺蠢的)
首先,想用递归,用字符串记录投掷选择,例如:“123”,即投掷顺序为1,2,3。但由于递归过程中会有重复投掷结果出现,就用了一个set存放,之后输出set.size()。

代码

#include <iostream>
#include <vector>
#include <set>
using namespace std;
  
int choice[6] = {1,2,3,4,5,6};
vector<int> method;
set<string> me;
  
void method_num(int n, string s){
    if (n == 0) {
        me.insert(s);
        return;
    }
    if (n >= 1)  {method_num(n-1,'1'+s); method_num(n-1,s+'1');}
    if (n >= 2) {method_num(n-2,'2'+s); method_num(n-2,s+'2');}
    if (n >= 3) {method_num(n-3,'3'+s); method_num(n-3,s+'3');}
    if (n >= 4) {method_num(n-4,'4'+s) ; method_num(n-4,s+'4');}
    if (n >= 5) {method_num(n-5,'5'+s) ; method_num(n-5,s+'5');}
    if (n >= 6) {method_num(n-6,'6'+s) ; method_num(n-6,s+'6');}
}
  
int main() {
    int n;
    cin>>n;
    method_num(n,"");
    cout << me.size()<<endl;
    return 0;
}

备注 这个题目里还有个条件,就是n在[1,6],所以对于这个题目,直接算好以后输出也行。

第二题 拼凑钱币

题目

给你六种面额 1、5、10、20、50、100 元的纸币,假设每种币值的数量都足够多,编写程序求组成N元(N为0~10000的非负整数)的不同组合的个数。

输入样例

1

输出样例

1

参考思路及答案
动态规划。参照https://blog.csdn.net/weixin_40255793/article/details/79634651:
首先,我们给纸币面额编号 0、1、2、3、4、5,面额数组p = {1, 5, 10, 20, 50, 100},定义 f(i, j) 表示用面额编号为 0、1、…i 的纸币面额,组成 j 元的组合个数。

分析:

首先,我们从最大面额 100 开始,1000 元的所有组合中,如果我们不使用面额 100(p[5]),那么问题就变成了用剩下的面额来组合 1000 元,即 f(4, 1000),如果我们使用面额 100(p[5]),那么我们至少使用了一张,问题可以简化为用面额数组表示剩下的 900 元,即 f(5, 900)。
所以 f(5, 1000)的组合个数为 f(4, 1000) 与 f(5, 1000 - p[5]) 的和。

因此我们可以得到 递推公式:

f(i, j) =
f(i-1, j) j 小于面额 p[i] 时
f(i-1, j) + f(i, j - p[i]) 大于时
f(i-1, j) + 1 等于时

代码
dp[j]是用money[1~j]这j种钱币的组合数:
Alt

#include <iostream>
using namespace std;
 
int money[6] = {1,5,10,20,50,100};
 
long long method_num(int n){
    long long dp[10001];
    for (int i=0;i<=n;i++) dp[i] = 0;
    dp[0] = 1;
    for(int i = 0;i < 6;++i){
        for(int j = 1;j <= n;++j){
            if (j>= money[i])
                dp[j] += dp[j-money[i]];
        }
 
    }
    return dp[n];
}
 
int main() {
    int n;
    cin>>n;
    cout<<method_num(n)<<endl;
    return 0;
}

第三题 最大矩形面积

题目

给定一组非负整数组成的数组h,代表一组柱状图的高度,其中每个柱子的宽度都为1。 在这组柱状图中找到能组成的最大矩形的面积(如图所示)。 入参h为一个整型数组,代表每个柱子的高度,返回面积的值。

Alt
输入样例

6

输出样例

32

思路
遍历每个数字x,left向左找到第一个比x小的,right向右找到第一个比x大的,求出面积x*(right-left+1),找出最大面积。

代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
int cal_area(vector<int> &a, int x){//计算面积
    int len = 0;
    int left = x, right = x;
    int high = a[x];
    while(a[left-1] >= high && left-1>=0) left--;
    while(a[right+1] >= high && right+1<=a.size()) right++;
    return high*(right-left+1);
}
 
int max_area(vector<int> &a) {//返回最大面积
    vector<int> area;
    for (int i = 0; i < a.size(); i++) {
        area.push_back(cal_area(a, i));
    }
    sort(area.begin(), area.end());
    return area[area.size() - 1];
}
 
int main()
{
    int n;
    vector<int> a;
    cin>>n;
    for (int i=0;i<n;i++){
        int k;
        cin>>k;
        a.push_back(k);
    }
 
    cout<<max_area(a)<<endl;
    return 0;
}

参考方法

链接:https://www.nowcoder.com/questionTerminal/b0fbb688d01a4f2c8c17e5efd85d5824
来源:牛客网

'''
分治法:最大矩形面积只可能有三种情况:
1. 取决于高度最小的柱子,此时面积等于高度乘总长度;
2. 最大面积出现在高度最小的柱子左边;
3. 最大面积出现在高度最小的柱子右边;
'''
n = int(raw_input())
h = [int(x) for x in raw_input().split()]
 
def largestarea(a):
    l = len(a)
    idx = a.index(min(a))
 
    value1 = a[idx] * l
 
    if idx != 0:
        value2 = largestarea(a[0:idx])
    else:
        value2 = 0
    if idx != l-1:
        value3 = largestarea(a[idx+1:l])
    else:
        value3 = 0
    return max(value1, value2, value3)
 
print largestarea(h)

第四题 最长公共连续子串

题目

给出两个字符串(可能包含空格),找出其中最长的公共连续子串,输出其长度。

输入样例

abcbdefbwd
bcbwd

输出样例

3

思路
参考https://blog.csdn.net/ten_sory/article/details/79857531

定义dp[i][j]的含义是:字符串 [a1,a2,…,ai]与字符串[b1,b2,…,bj]的最长公共连续子串的最后一个字符与这个两个字符串的最后一个字符相等的情况下,这个LCS的长度(不好理解)。因此状态转移方程为:
Alt

代码

#include <iostream>
#include <vector>
using namespace std;
 
int commen_string(string s1,string s2){
    vector<vector<int>> a;
    int x = s1.length(),y = s2.length();
    vector<int> bb;
    int max = 0;
 
    for (int i = 0;i < x; i++) {
        bb.clear();
        for (int j = 0; j < y; j++) {
            int len = 0;
            if (s1[i] == s2[j]) {
                if (i == 0 || j == 0) len = 1;
                else len = a[i - 1][j - 1] + 1;
            };
            if (len>max) max = len;
            bb.push_back(len);
        }
        a.push_back(bb);
    }
    return max;
}
 
int main(){
    string s1,s2;
    getline(cin,s1);
    getline(cin,s2);
    cout<<commen_string(s1,s2)<<endl;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值