8.9 字节跳动春招研发 雀魂启动!特征提取

牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)

3.雀魂启动!

小包最近迷上了一款叫做雀魂的麻将游戏,但是这个游戏规则太复杂,小包玩了几个月了还是输多赢少。

于是生气的小包根据游戏简化了一下规则发明了一种新的麻将,只留下一种花色,并且去除了一些特殊和牌方式(例如七对子等),具体的规则如下:

  1. 总共有36张牌,每张牌是1~9。每个数字4张牌。
  2. 你手里有其中的14张牌,如果这14张牌满足如下条件,即算作和牌
  • 14张牌中有2张相同数字的牌,称为雀头。
  • 除去上述2张牌,剩下12张牌可以组成4个顺子或刻子。顺子的意思是递增的连续3个数字牌(例如234,567等),刻子的意思是相同数字的3个数字牌(例如111,777)

例如:

1 1 1 2 2 2 6 6 6 7 7 7 9 9 可以组成1,2,6,7的4个刻子和9的雀头,可以和牌

1 1 1 1 2 2 3 3 5 6 7 7 8 9 用1做雀头,组123,123,567,789的四个顺子,可以和牌

1 1 1 2 2 2 3 3 3 5 6 7 7 9 无论用1 2 3 7哪个做雀头,都无法组成和牌的条件。

现在,小包从36张牌中抽取了13张牌,他想知道在剩下的23张牌中,再取一张牌,取到哪几种数字牌可以和牌。

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 32M,其他语言64M

输入描述:

输入只有一行,包含13个数字,用空格分隔,每个数字在1~9之间,数据保证同种数字最多出现4次。

输出描述:

输出同样是一行,包含1个或以上的数字。代表他再取到哪些牌可以和牌。若满足条件的有多种牌,请按从小到大的顺序输出。若没有满足条件的牌,请输出一个数字0

示例1

输入例子:

1 1 1 2 2 2 5 5 5 6 6 6 9

输出例子:

9

例子说明:

可以组成1,2,6,7的4个刻子和9的雀头

示例2

输入例子:

1 1 1 1 2 2 3 3 5 6 7 8 9

输出例子:

4 7

例子说明:

用1做雀头,组123,123,567或456,789的四个顺子

示例3

输入例子:

1 1 1 2 2 2 3 3 3 5 7 7 9

输出例子:

0

例子说明:

来任何牌都无法和牌

思路:对于接收到的13张牌,依次新增1-9,再引入IsHe函数判断是否当前14张牌是和牌,可和牌则输出该新增的值。

编程实现:递归算法 : 从最小的数字开始尝试,如果能把其当成雀头成员(个数大于等于3且牌的总数不能被3整除),该数字划掉两个,并看余下的数字能否划空如果是刻子成员,该数字划掉三个,并查看余下数字能否划空如果是顺子成员,划掉该值 a ,a+1,a+2,并查看余下数字能否划空如果上述三种尝试都无法划空数组,说明存在数字无法是 雀头、刻子、顺子的成员, 即无法胡牌。上述任何一种情况能划空数组,都可以胡牌)  
 

代码:取自牛客网的评论区nbgao

#include <bits/stdc++.h>
using namespace std;

bool IsHe(map<int,int> M, int t){
    if(t<=0)
        return true;
    while(M[M.begin()->first]==0)
        M.erase(M.begin());
    map<int,int>::iterator it = M.begin();
    int i=it->first, cnt=it->second;
    if(t%3!=0 && cnt>=2){
        M[i] -= 2;
        if(F(M, t-2))
            return true;
        M[i] += 2;
    }
    if(cnt>=3){
        M[i] -= 3;
        if(F(M, t-3))
            return true;
        M[i] += 3;
    }
    if(cnt>0 && M[i+1]>0 && M[i+2]>0){
        M[i]--;
        M[i+1]--;
        M[i+2]--;
        if(F(M, t-3))
            return true;
        M[i]++;
        M[i+1]++;
        M[i+2]++;
    }
    return false;
}

int main(){
    map<int, int> M;
    int x;
    for(int i=0;i<13;i++){
        cin>>x;
        M[x]++;
    }
    vector<int> v;
    for(int i=1;i<10;i++){
        if(M[i]<4){
            M[i]++;
            if(IsHe(M, 14))
                v.push_back(i);
            M[i]--;
        }
    }
    if(v.empty())
        cout<<0<<endl;
    else{
        for(int i=0;i<v.size();i++){
            if(i==v.size()-1)
                cout<<v[i]<<endl;
            else
                cout<<v[i]<<" ";
        }
    }

    return 0;
}

4.特征提取

小明是一名算法工程师,同时也是一名铲屎官。某天,他突发奇想,想从猫咪的视频里挖掘一些猫咪的运动信息。为了提取运动信息,他需要从视频的每一帧提取“猫咪特征”。一个猫咪特征是一个两维的vector<x, y>。如果x_1=x_2 and y_1=y_2,那么这俩是同一个特征。

       因此,如果喵咪特征连续一致,可以认为喵咪在运动。也就是说,如果特征<a, b>在持续帧里出现,那么它将构成特征运动。比如,特征<a, b>在第2/3/4/7/8帧出现,那么该特征将形成两个特征运动2-3-4 和7-8。

现在,给定每一帧的特征,特征的数量可能不一样。小明期望能找到最长的特征运动。

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 32M,其他语言64M

输入描述:第一行包含一个正整数N,代表测试用例的个数。 每个测试用例的第一行包含一个正整数M,代表视频的帧数。 接下来的M行,每行代表一帧。其中,第一个数字是该帧的特征个数,接下来的数字是在特征的取值;比如样例输入第三行里,2代表该帧有两个猫咪特征,<1,1>和<2,2> 所有用例的输入特征总数和<100000 N满足1≤N≤100000,M满足1≤M≤10000,一帧的特征个数满足 ≤ 10000。 特征取值均为非负整数。

输出描述:对每一个测试用例,输出特征运动的长度作为一行

示例1

输入例子:

1
8
2 1 1 2 2
2 1 1 1 4
2 1 1 2 2
2 2 2 1 4
0
0
1 1 1
1 1 1

输出例子:

3

例子说明:特征<1,1>在连续的帧中连续出现3次,相比其他特征连续出现的次数大,所以输出3

思路:求最长的连续<v1,v2>,可用动归的思想。

如何保存状态:先明确是pair<int,int>的值,还要保存当前每个pair<int,int>的次数(方便计算状态)用unordered_map<pair<int, int>, int,hash_pair> cur(hash_pair为自己写的一个hash函数)

状态迭代:新行创建一个新的unordered_map m2,再遍历该行所有pair<int, int>,对于每一个pair的val次数值=上一行的状态m1[pair]+1

#include <iostream>
#include <utility>
#include <vector>
#include <unordered_map>
using namespace std;
struct hash_pair {
    template <class T1, class T2>
    size_t operator()(const pair<T1, T2>& p) const {
        auto hash1 = hash<T1> {}(p.first);
        auto hash2 = hash<T2> {}(p.second);
        return hash1 ^ hash2;
    }
};
int main() {
    int n;
    cin >> n;
    while (n--) {
        int num;
        cin >> num;
        unordered_map<pair<int, int>, int,hash_pair> cur;
        int max = 0;
        for (int i = 0; i < num; i++) {
            int size;
            cin >> size;
            unordered_map<pair<int, int>, int,hash_pair> temp_map;
            for (int i = 0; i < size; i++) {
                int temp1, temp2;
                cin >> temp1 >> temp2;
                pair<int,int> p=make_pair(temp1, temp2);
                temp_map[p]=cur[p]+1;
                if(temp_map[p]>=max){
                    max=temp_map[p];
                }
            }
            cur=temp_map;
        }
        cout<<max<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值