美团2018.3.22编程题

本文探讨了两个算法问题:字符串距离计算与受限字符集下不可构造的最小正整数。针对字符串距离问题,提出了基于滑动窗口的方法,并通过动态维护计数数组实现了O(n)的高效解决方案。对于数字字符问题,则采用贪心策略确定不可构造的最小正整数。
摘要由CSDN通过智能技术生成

昨天比较忙,今天抽空写一下,毕竟自己没做的太好(主要是因为刚面试回来,头极晕,肚子极饿等等),还是总结一下好。


第一题:字符串距离

题目:

给出两个相同长度的由字符 a 和 b 构成的字符串,定义它们的距离为对应位置不同的字符的数量。如串”aab”与串”aba”的距离为 2;串”ba”与串”aa”的距离为 1;串”baa”和串”baa”的距离为 0。下面给出两个字符串 S 与 T,其中 S 的长度不小于 T 的长度。我们用|S|代表 S 的长度,|T|代表 T 的长度,那么在 S 中一共有|S|-|T|+1 个与T长度相同的子串,现在你需要计算 T 串与这些|S|-|T|+1 个子串的距离的和。

输入描述:

第一行包含一个字符串 S。第二行包含一个字符串 TS 和 T 均由字符 a 和 b 组成,1 ≤ |T| ≤ |S| ≤105 。

输出描述:

输出对应的答案。

样例:

in:
aab
aba
out:
2
in:
aaabb
bab
out:
5

思路:看了第一眼竟然想到的是kmp算法。。。后来仔细思考,发现他这里存在一个每个字符的贡献问题,如果对S串进行逐位看的话,在【1,T 】的范围内,S串的字符与T串参与比较的数量增加直到等于T,然后中间部分一直是等于T的,最后的部分【S-T+1, S】的范围内,数量则是逐渐递减。然后可以动态维护一个数组cnt[2](如果题目换成了26个字母的话,就是cnt[26]),然后保存在S串当前位置,T串会参与比较的字符的对应数量,比如,S串的第五个位置有2个a,3个b,那么该位置对结果的贡献很显然可以再O(1)的时间内算出来,而这个动态数组的维护也是O(1),所以总复杂度只是O(n).

代码:

#include<iostream>
#include<fstream>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdio.h>
#include<utility>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>
#define f(a, b) (a) > (b) ? (a) : (b)
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int INF = 1<<30;
const ll llINF = 1e18+999;

const int maxn = 1e5 + 5;

char s[maxn], t[maxn];

int main(int argc, char const *argv[]) {
    
    scanf("%s%s", s, t);

    int lens = strlen(s);
    int lent = strlen(t);

    int cnt[30];
    memset(cnt, 0, sizeof(cnt));
    long long ans = 0;
    int window = 0;

    int p = lens - lent, q = 0;
    for (int i = 0; i < lens; i ++) {
        if (q < lent) {
            cnt[t[q] - 'a'] ++;
            window ++;
            q ++;
        }
        if (i > p) {
            cnt[t[i - p - 1] - 'a'] --;
            window --;
        }
        // cout << i << " " << max(0, i - p) << " " << q << " " << window << endl;
        ans += 1ll * (window - cnt[s[i] - 'a']);
    }

    cout  << ans << endl;

    return 0;
}

第二题:数字字符

题目:

在十进制表示中,任意一个正整数都可以用字符‘0’-‘9’表示出来。但是当‘0’-‘9’这些字符每种字符的数量有限时,可能有些正整数就无法表示出来了。比如你有两个‘1’,一个‘2’ ,那么你能表示出 11,12,121 等等,但是无法表示出 10,122,200 等数。 
  
现在你手上拥有一些字符,它们都是‘0’-‘9’的字符。你可以选出其中一些字符然后将它们组合成一个数字,那么你所无法组成的最小的正整数是多少?

输入描述:

第一行包含一个由字符’0’-‘9’组成的字符串,表示你可以使用的字符。1 ≤ 字符串长度 ≤ 1000

输出描述:

输出你所无法组成的最小正整数。

样例:

in:
55
out:
1
in:
123456789
out:
10

思路:首先提一下,不能用int存结果的。考试时候没有ac,是理解错了题。题中说的是不能凑出的最小的正整数,那么首先想到有两种贪心策略,其一优先取位数少的,第二优先取高位数小的。考试的时候就是这里搞错了,这里有一个很重要的地方,那就是答案一定是某一个数被重复了n次的,或者是1加上0被重复n次(因为不能出现前导0),这里想明白了,就很简单了,直接暴力统计,比较,打印就好了。

代码:

#include<iostream>
#include<fstream>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdio.h>
#include<utility>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>
#define f(a, b) (a) > (b) ? (a) : (b)
using namespace std;
typedef long long ll;
const int maxn = 1e3+5;
const int mod = 1e9+7;
const int INF = 1<<30;
const ll llINF = 1e18+999;

char in[maxn];
int main(int argc, char const *argv[]) {

    while(~scanf("%s", in))
    {
        int n = strlen(in), Count[10] = {0};
        for(int i=0; i<n; i++)
            Count[in[i]-'0']++;
        Count[0]++;//0特殊,第一位不能出现

        int minCount = maxn, value = 0;
        for(int i=0; i<10; i++)
        {
            if(Count[i]<minCount)
            {
                minCount = Count[i];
                value = i;
            }
        }

        if(value == 0)//如果是0最少
        {
            cout<<1;
            while(minCount--)
            {
                cout<<0;
            }
        }
        else
        {
            minCount++;
            while(minCount--)
                cout<<value;
        }
        cout<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值