深信服2019 算法题

210 阅读2分钟

题目一:子串模糊匹配

题目: 从字符串string开始完整匹配子串sub,返回匹配到的字符个数。

sub中如果出现'?'表示可以匹配一到三个除'\0'以外的任意字符。
如果sub还有找不到匹配的字符,则说明不能完整匹配。

如果能完整匹配,返回匹配到的字符个数,如果有多种匹配方式,返回匹配字符数最少的那个,如果不能完整匹配,返回-1

正则表达式:

let str = readline();
let key = readline();
let re = key.split("?");
re = "^"+re.join(".{1,3}?");
re = RegExp(re);
const res = re.exec(str);
console.log(res ? res[0].length : -1);

题目二:

题目: 有K种颜色的小球(K<=10),每种小球有若干个,总数小于100个。
现在有一个小盒子,能放N个小球(N<=8),现在要从这些小球里挑出N个小球,放满盒子。
想知道有哪些挑选方式。注:每种颜色的小球之间没有差别。

请按数字递增顺序输出挑选小球的所有方式。

如有3种颜色,每种颜色小球的个数分别为a:1,b:2,c:3,挑出3个小球的挑法有:
003,012,021,102,111,120

#include <iostream>
#include<vector>
#include<numeric>
using namespace std;
struct node{
	int num;
	vector<vector<int> > v;
};
int main(){
	int K, N,Ki;
	cin >> K >> N;
	vector<node> ball(K);
	for(int i=0;i<K;i++){
		node p;
		cin>>Ki;
		ball[i].num=Ki;
	}
	if(K==1) cout<<N<<endl;
	else {
		vector<int> tmpv;
		for(int i=0;i<=ball[0].num;i++)	{
			tmpv.push_back(i);
			ball[0].v.push_back(tmpv);
			tmpv.clear();
		}
		for(int i=1;i<K;i++){	
			for(int j=0;j<ball[i-1].v.size();j++){
				for(int k=0;k<=ball[i].num;k++){
					tmpv=ball[i-1].v[j];
					tmpv.push_back(k);
					if(i==K-1){
						if(accumulate(tmpv.begin(),tmpv.end(),0)==N){
							for(int l=0;l<tmpv.size();l++) cout<<tmpv[l];
							cout<<endl;
						}
					}
					else {
						if(accumulate(tmpv.begin(),tmpv.end(),0)<=N) ball[i].v.push_back(tmpv);
					}
					tmpv.clear();
				}
			}
		}
	}
}

题目三:下棋

题目: 8x8的棋盘上,布有黑白两色棋子,白子先下,当白子下N手后,棋盘上最多有可能留下多少颗白子?

下法规则:
1.每次落子后,以该棋子为中心的8个方向(米字形的8条直线),如果有同色棋子,
且两个同色棋子之间连续排列着若干个异色棋子,无空白及同色棋子。则,这次落子可以把这些夹在中间的异色棋子全部翻色(即黑变白,白变黑)。

2. 黑白子交错落子。

3. 如果一个位置上有棋子,不能继续在该位置上落子;

4. 如果一个位置上落子后,不能翻对手的棋子,则该位置不能落子;

1表示黑色,2表示白色,0表示空白未落子
白棋落子后,棋盘变化情况如下所示:
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 1 2 0 0 0    =>   0 0 0 1 2 0 0 0 
0 0 0 2 1 0 0 0         0 0 0 2 2 2 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 

0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 1 2 0 0 0    =>   0 0 0 1 2 0 0 0 
0 0 1 2 1 2 0 0         0 0 1 2 1 1 1 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0         0 0 0 0 0 0 0 0

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define ll long long
using namespace std;
typedef pair<int,int> p;


int mp[8][8];
int dir[8][2]={-1,0,1,0,0,-1,0,1,-1,-1,-1,1,1,-1,1,1};//上,下,左,右,左上,右上,左下,右下
int n,ans;

int find_sum(int x,int y,int dx,int dy,int nwcolor,int others)
{
    int cnt=1;
    x+=dx; y+=dy;
    while(x>=0&&x<8&&y>=0&&y<8)
    {
        if(mp[x][y]==nwcolor)
            return cnt;
        if(mp[x][y]!=others)
            return 0;
        x+=dx;
        y+=dy;
        cnt++;
    }
    return 0;
}
void dfs(int step)
{
    if(step==n)
    {
        int cnt=0;
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<8; j++)
                if(mp[i][j]==2) cnt++;
        }
        ans=max(ans,cnt);
        return;
    }
    int nw,lst;
    vector<p> g;//保存要改变的棋子位置
    if(step%2==0)
    {
        nw=2;
        lst=1;
    }
    else
    {
        nw=1;
        lst=2;
    }
    for(int i=0; i<8; i++)
    {
        for(int j=0; j<8; j++)
        {
            if(mp[i][j]==0)
            {
                int flag=0;//回溯标记
                for(int k=0; k<8; k++)
                {
                    int cnt=find_sum(i,j,dir[k][0],dir[k][1],nw,lst);//从当前位置[i,j]沿当前方向可以改变多少个棋子
                    if(cnt>1)
                    {
                        int x=i,y=j;
                        for(int ii=0; ii<cnt; ii++)
                        {
                            mp[x][y]=nw;
                            g.push_back(make_pair(x,y));//保存要更新的棋子位置
                            x+=dir[k][0];
                            y+=dir[k][1];
                        }
                        flag=1;
                    }
                }
                if(flag)
                {
                    dfs(step+1);
                    for(int ii=0; ii<g.size(); ii++)//回溯
                    {
                        mp[g[ii].first][g[ii].second]=lst;
                    }
                    mp[i][j]=0;
                    g.clear();
                }
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    n=2*n-1;
    for(int i=0; i<8; i++)
    {
        for(int j=0; j<8; j++)
        {
            scanf("%d",&mp[i][j]);
        }
    }
    ans=0;
    dfs(0);
    printf("%d\n",ans);
    return 0;
}

题目四:

题目: 一个长方体,长宽高分别为x,y,z,都为自然数。

现在要把若干个相同的长方体摆成高为N的一根柱形体。

每层摆1个,如果两种摆法的高度是一样的,则认为这两种摆法等价,所以每层只有三种摆法。

求一共有多少种摆法。

#include<iostream>
using namespace std;
int x,y,z;
int dp(int n,int l){
    if(l>n)
        return 0;
    else{
        if(l==n)
            return 1;
        return dp(n-l,x)+dp(n-l,y)+dp(n-l,z);
    }
}
int main(){
    int N;
    cin>>N>>x>>y>>z;
    int r=dp(N,x)+dp(N,y)+dp(N,z);
    cout<<r;
    return 0;
}

题目五:IP段合并

题目: 一个数字段由首尾两个数字标识,表示一个自然数集合,
比如数字段[beg, end)表示从beg到end之间的所有自然数,
包含beg,但不包含end。

有若干个数字段,这些数字段之间可能有重叠,
怎么把这些数字段合并去重,用最少个数的数字段来表示。

合并前后,整个集合包含的数字不发生变化。

import sys

if __name__ == '__main__':
    N = int(sys.stdin.readline().strip())
    raw_input = []
    for line in sys.stdin:
        raw_input.append(list(map(int, line.split())))
    raw_input.sort(key=lambda x:x[0])
    res = [raw_input[0]]
    for value in raw_input:
        if value[0] <= res[-1][1]:
            res[-1][1] = max(res[-1][1], value[1])
        else:
            res.append(value)
    for interval in res:
        print('{} {}'.format(interval[0], interval[1]))

题目六:查找重复序列

题目: 已知某序列S=<e1,e2,…,en>,序列中的元素类型为整数(en <= 2^10),序列的长度为可变长度。
现在有若干序列S1,S2,…,Sn,现在要求设计一种算法,找出这些重复的序列。输出重复序列的序号,如果有多组重复,需全部输出。

所有序列中的数字个数加起来,小于1000000,序列个数小于10000个。

例如现有3个序列
S1=<65,43,177,655>
S2=<1,2,3,4,5,6,7>
S3=<65,43,177,655,3>
这时序列无重复。又如
S1=<65,43,177,655,3>
S2=<1,2,3,4,5,6,7>
S3=<65,43,177,655,3>
这时序列有重复。

from collections import OrderedDict
if __name__ == '__main__':
    N = int(input())
    res = OrderedDict()
    for i in range(N):
        input()
        hash_code = hash(input())
        if hash_code in res:
            res[hash_code].append(i)
        else:
            res[hash_code] = [i]
    is_find = False
    for k, v in res.items():
        if len(v) > 1:
            is_find = True
            print(*v)
    if not is_find:
        print('no')