题意
这题目描述真的考语文呢,
给数组A(0-index),B
- 给B排序去重
- 遍历B,对每个值,找A中十进制表示中包含该值的下标,和A中的那个值
- 除此以外还有,还要输出每个值,输出下标的个数,在找不到时不输出,还要输出所有值的总个数
- 所以输出格式是
总数, [B中的值, 下标个数, [A中下标, A中的值,] ]
范围, 每个值 非负且不大于0xffffffff
方法
数值转换成字符串
我们把数组用 sort 进行排序,并利用b[i] != b[i-1]
忽略掉重复.
此后就是朴素的实现题意即可
先遍历数组B,每次遍历数组A,如果满足字符包含,则记录下标。
对于每一个B的遍历,在统计完下标后再进行输出转换。
在所有统计完后就能得到输出总数了。
其中十进制包含我们使用sprintf
完成数字到字符串的转换,strstr
来完成字符串包含关系的检测
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(ll i = (a);i<(b);i++)
bool vinv(ll v0,ll v1){ // v0 是否在 v1 中
char s0[20];
char s1[20];
rep(i,0,20)s0[i]=s1[i]=0;
sprintf(s0,"%lld",v0); // 转换成字符串
sprintf(s1,"%lld",v1); // 转换成字符串
return strstr(s1,s0) != NULL; // 字符串搜索
}
int main(){
int n,m;
while(~scanf("%d",&n)){
vector<ll> a;
rep(i,0,n){
ll v;
scanf("%lld",&v);
a.push_back(v); // 读入a
}
scanf("%d",&m);
vector<ll> b;
rep(i,0,m){
ll v;
scanf("%lld",&v);
b.push_back(v); // 读入b
};
sort(b.begin(),b.end());
vector<ll> ans;
rep(i,0,m){
if(i > 0 && b[i] == b[i-1])continue; // 忽略重复
vector<ll>idxs = {};
rep(j,0,n){
if(vinv(b[i],a[j])){
idxs.push_back(j);
}
}
if(idxs.size()){
ans.push_back(b[i]);
ans.push_back(idxs.size());
for(auto idx:idxs){
ans.push_back(idx);
ans.push_back(a[idx]);
}
}
}
printf("%d",int(ans.size()));
for(auto v: ans){
printf(" %lld", v);
}
printf("\n");
}
return 0;
}
复杂度分析
设数组B的大小为m,数组A的大小为n
时间复杂度: 最开始对数组B排序为O(m⋅log(m)),对于查找满足条件的先循环数组B再每次从A中查找,所以是双重循环,所以时间复杂度为O(mn)
空间复杂度: 空间一部分是用在读入数据O(m+n),另一部分是记录结果,而结果最坏情况是两两都匹配,所以空间复杂度也是O(mn)
基于十进制比较
其中, 判断包含关系的通过十进制的移位来比较
以样例数据中,3 是否包含在 453456中为例
vinv函数 | v0 | v1 | b | 结果((v0/b)%10 != (v1/b)%10 ) |
---|---|---|---|---|
入参 | 3 | 453456 | 未初始化 | |
3 | 453456 | 1 | 3 != 6, 不属于 | |
3 | 45345 | 1 | 3 != 5, 不属于 | |
3 | 4534 | 1 | 3 != 4, 不属于 | |
3 | 453 | 1 | 3 == 3, 属于返回 true |
需要注意的是,0需要特殊处理。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(ll i = (a);i<(b);i++)
bool vinv(ll v0,ll v1){ // v0 是否在 v1 中
if(v0 == 0){ // 零特殊检查
if(v1 == 0)return true;
while(v1 != 0){
if(v1 % 10 ==0)return true;
v1/=10;
}
return false;
}
while(v0 <= v1){
ll b = 1; // 按位检查
bool eq = true;
while(b <= v0){
if( (v0/b)%10 != (v1/b)%10 )eq = false;
b*=10;
}
if(eq)return true;
v1/=10; // 移动v1 再次对比
}
return false;
}
int main(){
int n,m;
while(~scanf("%d",&n)){
vector<ll> a;
rep(i,0,n){
ll v;
scanf("%lld",&v);
a.push_back(v); // 读入a
}
scanf("%d",&m);
vector<ll> b;
rep(i,0,m){
ll v;
scanf("%lld",&v);
b.push_back(v); // 读入b
};
sort(b.begin(),b.end());
vector<ll> ans;
rep(i,0,m){
if(i > 0 && b[i] == b[i-1])continue; // 忽略重复
vector<ll>idxs = {};
rep(j,0,n){
if(vinv(b[i],a[j])){
idxs.push_back(j); // 包含则记录 下标
}
}
if(idxs.size()){ // 按照要求输出储存数据
ans.push_back(b[i]);
ans.push_back(idxs.size());
for(auto idx:idxs){
ans.push_back(idx);
ans.push_back(a[idx]);
}
}
}
printf("%d",int(ans.size()));
for(auto v: ans){
printf(" %lld", v);
}
printf("\n");
}
return 0;
}
复杂度分析
时间复杂度: 最开始对数组B排序为O(m⋅log(m)),对于查找满足条件的先循环数组B再每次从A中查找,所以是双重循环,所以时间复杂度为O(mn)
空间复杂度: 空间一部分是用在读入数据O(m+n),另一部分是记录结果,而结果最坏情况是两两都匹配,所以空间复杂度也是O(mn)