微软2014实习生在线测试题

1.String reorder


Time Limit: 10000ms
Case Time Limit: 1000ms
Memory Limit: 256MB

Description:


For this question, your program is required to process an input string containing only ASCII characters between ‘0’ and ‘9’, or between ‘a’ and ‘z’ (including ‘0’, ‘9’, ‘a’, ‘z’). 

Your program should reorder and split all input string characters into multiple segments, and output all segments as one concatenated string. The following requirements should also be met,
1. Characters in each segment should be in strictly increasing order. For ordering, ‘9’ is larger than ‘0’, ‘a’ is larger than ‘9’, and ‘z’ is larger than ‘a’ (basically following ASCII character order).

2. Characters in the second segment must be the same as or a subset of the first segment; and every following segment must be the same as or a subset of its previous segment. 


Your program should output string “<invalid input string>” when the input contains any invalid characters (i.e., outside the '0'-'9' and 'a'-'z' range).

Input


Input consists of multiple cases, one case per line. Each case is one string consisting of ASCII characters.

Output

For each case, print exactly one line with the reordered string based on the criteria above.

Sample In


aabbccdd
007799aabbccddeeff113355zz
1234.89898
abcdefabcdefabcdefaaaaaaaaaaaaaabbbbbbbddddddee

Sample Out


abcdabcd
013579abcdefz013579abcdefz
<invalid input string>

abcdefabcdefabcdefabdeabdeabdabdabdabdabaaaaaaa


思路:字符串只包含10个数字和26个小写字母,因此可以扫描一遍字符串,统计每个字符出现的次数,再依次打印即可。


#include <stdio.h>

void string_reorder(char *s)
{
    int count[36] = {0};
    int i, max;
    
    i = 0;
    max = 0; //记录某个字符出现的最大次数
    while (s[i] != '\0') {
        if ((s[i] <= '9') && (s[i] >= '0')) {
            count[s[i]-'0']++;
            if (max < count[s[i]-'0'])
                max = count[s[i]-'0'];
        }
        else if ((s[i] <= 'z') && (s[i] >= 'a')) {
            count[s[i]-'a'+10]++;
            if (max < count[s[i]-'a'+10])
                max = count[s[i]-'a'+10];
        }
        else {
            printf("<invalid input string>\n");
            return;
        }
        i++;
    }
    
    while (max--) {
        for (i = 0; i < 36; i++) {
            if (count[i] > 0) {
                if (i%36 < 10) {
                    printf("%c", '0'+(i%36));
                }
                else {
                    printf("%c", 'a'+(i%36)-10);
                }
                count[i]--;
            }
        }
    }
    printf("\n");
}

int main(void)
{
    char s[100];
    while (scanf("%s", s) != EOF) {
        string_reorder(s);
    }
    return 0;
}

2.K-th string


Time Limit: 10000ms
Case Time Limit: 1000ms

Memory Limit: 256MB


Description:


Consider a string set that each of them consists of {0, 1} only. All strings in the set have the same number of 0s and 1s. Write a program to find and output the K-th string according to the dictionary order. If s​uch a string doesn’t exist, or the input is not valid, please output “Impossible”. For example, if we have two ‘0’s and two ‘1’s, we will have a set with 6 different strings, {0011, 0101, 0110, 1001, 1010, 1100}, and the 4th string is 1001.

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10000), the number of test cases, followed by the input data for each test case.
Each test case is 3 integers separated by blank space: N, M(2 <= N + M <= 33 and N , M >= 0), K(1 <= K <= 1000000000). N stands for the number of ‘0’s, M stands for the number of ‘1’s, and K stands for the K-th of string in the set that needs to be printed as output.

Output

For each case, print exactly one line. If the string exists, please print it, otherwise print “Impossible”.

Sample In

3
2 2 2
2 2 7
4 7 47

Sample Out

0101
Impossible

01010111011


思路:N个‘0’,M个‘1’,根据排列组合,一共有C(N, M+N)种可能,若K大于此值,则必然Impossible。

然后对结果从高位到低位分析,若第1位为‘0’,则剩余的数字中有(N-1)个‘0’,M个‘1’,共有C(N-1, M+N-1)中可能:

若K < C(N-1, M+N-1),则第1位为‘0’;

若K > C(N-1, M+N-1),则第1位为‘1’,K=K-C(N-1, M+N-1);

若K = C(N-1, M+N-1),则第1位为‘0’,接下来M位均为‘1’,剩下的(N-1)位为‘0’;

以此类推。

#include <stdio.h>
#include <assert.h>

#define bool int
#define true 1
#define false 0
#define MAXK 1000000000

bool judge(int n, int m, int k, unsigned long long *result)
{
    unsigned long long res = 1;
    int i;
    int a, b;
    
    if (n < m) { //减少计算次数
        a = m;
        b = n;
    }
    else {
        a = n;
        b = m;
    }
    for (i = a + 1; i <= (m + n); i++) {
        res *= i;
        while ((b > 0) && (res%b == 0)) { //避免出现小数
            res /= b;
            b--;
        }
    }
    *result = res;
    if (res >= k)
        return true;
    else     
        return false;
}

int main(void)
{
    int n, m, count;
    unsigned long long k, result;
    int i, j;
    
    scanf("%d", &count);
    while (count--) {
        scanf("%d %d %llu", &n, &m, &k);
        
        assert((n >= 0) && (m >= 0));
        assert(((n+m) >= 2) && ((n+m) <= 33));
        assert((k >= 1) && (k <= MAXK));
        
        if (!judge(n, m, k, &result)) {
            printf("Impossible\n");
            continue;
        }
        
        if (n == 0) {
            while (m--)
                printf("%c", '1');
        }
        if (m == 0) {
            while (n--)
                printf("%c", '0');
        }
        
        while ((n >= 1) && (m >= 0)) {            
            result = 0;
            if (judge(n-1, m, k, &result)) { // result >= k
                printf("%c", '0');
                n--;
                if (k == result) {
                    while (m--)
                        printf("%c", '1');
                    while (n--)
                        printf("%c", '0');
                }
            }
            else { // result < k
                printf("%c", '1');
                m--;
                k -= result;
            }
        }
        printf("\n");
    }
    return 0;
}

3.Reduce inversion count


Time Limit: 10000ms
Case Time Limit: 1000ms
Memory Limit: 256MB

Description:

Find a pair in an integer array that swapping them would maximally decrease the inversion count of the array. If such a pair exists, return the new inversion count; otherwise returns the original inversion count.

Definition of Inversion: Let (A[0], A[1] ... A[n]) be a sequence of n numbers. If i < j and A[i] > A[j], then the pair (i, j) is called inversion of A.

Example:
Count(Inversion({3, 1, 2})) = Count({3, 1}, {3, 2}) = 2
InversionCountOfSwap({3, 1, 2})=>
{
  InversionCount({1, 3, 2}) = 1 <-- swapping 1 with 3, decreases inversion count by 1
  InversionCount({2, 1, 3}) = 1 <-- swapping 2 with 3, decreases inversion count by 1
  InversionCount({3, 2, 1}) = 3 <-- swapping 1 with 2 , increases inversion count by 1
}

Input

Input consists of multiple cases, one case per line.Each case consists of a sequence of integers separated by comma.

Output

For each case, print exactly one line with the new inversion count or the original inversion count if it cannot be reduced.

Sample In

3,1,2
1,2,3,4,5

Sample Out

1
0


思路:对于每一对逆序数(a[i], a[j]),交换之,逆序数必然减小。遍历数组,找到每一对逆序数(a[i], a[j]),由于交换这两个数,只会影响a[i]到a[j]之间的逆序对的数目,所以计算交换每一对逆序数之后最大的减少量即可。有更好的办法欢迎赐教。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}


//预判:有逆序对则返回1,否则返回0
int judge(int a[], int n)
{
    int i;
    for (i = 0; i < (n-1); i++) {
        if (a[i] > a[i+1])
            return 1;
    }
    return 0;
}


//计算a[begin]到a[end]之间的逆序对数
int inversion_count(int a[], int begin, int end)
{
    int count = 0;
    int i, j;
    for (i = begin; i < end; i++) {
        for (j = i+1; j <= end; j++) {
            if (a[i] > a[j])
                count++;
        }
    }
    return count;
}


int reduce_inversion_count(int a[], int n)
{
    int i, j;
    int count = 0;
    int before, after;
    int reduce = 0;


    for (i = 0; i < (n-1); i++) {
        for (j = i+1; j < n; j++) {
            if (a[i] > a[j]) {
                count++;
                before = inversion_count(a, i, j);
                swap(&a[i], &a[j]);
                after = inversion_count(a, i, j);
                swap(&a[i], &a[j]);
                if (reduce < (before - after)) {
                    reduce  = before - after;
                }
            }
        }
    }
    return count - reduce;
}


int main(void)
{
    char s[200];
    char *p;
    int a[200], i;


    while (scanf("%s", s) != EOF) {
        i = 0;
        p = strtok(s, ",");
        a[i++] = atoi(p);
        while ((p = strtok(NULL, ",")) != NULL) {
            a[i++] = atoi(p);
        }
        
        if (judge(a, i)) {
            printf("%d\n", reduce_inversion_count(a, i));
        }
        else {
            printf("%d\n", 0);
        }
    }
    return 0;
}

4.Most Frequent Logs


Time Limit: 10000ms
Case Time Limit: 3000ms
Memory Limit: 256MB

Description

In a running system, there're many logs produced within a short period of time, we'd like to know the count of the most frequent logs.
Logs are produced by a few non-empty format strings, the number of logs is N(1=N=20000), the maximum length of each log is 256.
Here we consider a log same with another when their edit distance (see note) is = 5.
Also we have a) logs are all the same with each other produced by a certain format string b) format strings have edit distance  5 of each other.
Your program will be dealing with lots of logs, so please try to keep the time cost close to O(nl), where n is the number of logs, and l is the average log length.
Note edit distance is the minimum number of operations (insert delete replace a character) required to transform one string into the other, please refer to edit distance for more details.

Input

Multiple lines of non-empty strings.

Output

The count of the most frequent logs.

Sample In

Logging started for id:1
Module ABC has completed its job
Module XYZ has completed its job
Logging started for id:10
Module ? has completed its job

Sample Out

3


求编辑距离:

采用动态规划,寻找子问题时,对于两个字符串X=A1...An和Y=B1..Bm,从后往前看,若它们的最后一个字符是相同的,则只需计算A1..An-1和B1...Bm-1的距离就可以了;若它们的最后一个字符不同,则可以通过以下操作来达到相同:

1. 通过删除字符串X的末尾字符An 或者 将An插入到字符串Y的末尾,然后再计算A1...An-1和B1...Bm的距离;

2.与情况1操作相反,删除字符串Y的末尾字符Bm 或者将Bm插入到字符串X的末尾,然后再计算A1...An和B1...Bm-1的距离;

3.修改字符串X的末尾字符为Bm 或者修改字符串Y的末尾字符为An,然后再计算A1...An-1和B1...Bm-1的距离。

使用dp[i][j]表示字符串Xi和Yj(i, j分别为字符串X和Y的长度)的编辑距离,若某一个串的长度为0,则编辑距离就是另一个串的长度。状态转移方程如下:

dp[i][j] = 0   如果i=0且j=0

dp[i][j] = xlen | ylen   如果j=0 | i =0

dp[i][j] = dp[i-1][j-1]   如果X[i-1] = Y[j-1]

dp[i][j] = 1 + min{dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}   如果X[i-1] != Y[j-1]


本题中对于same log的定义是,log之间有固定的格式,log之间的编辑距离<=5.

使用C++中的map来实现,key为log字符串,value为该类型字符串出现的次数。每一类型的log在map中只存放一条。

对于一条新日志string,遍历map中的每一条日志,如与string的编辑距离<=5,则该key对应的value加1,若map中不存在与string的编辑距离<=5的key,则将string插入到map中,string对于的次数为1. C++实现代码如下:

#include <iostream>
#include <string>
#include <map>

using namespace std;

int dp[257][257];

int min(int a, int b, int c)
{
    int t;
    t = (a < b) ? a : b;
    return ((t < c) ? t : c);
}

int edit_distance(const string s1, const string s2)
{
    int len1, len2, i, j;
	len1 = s1.length();
	len2 = s2.length();
    
    dp[0][0] = 0;
    for (i = 1; i <= len1; i++)
        dp[i][0] = i;
    for (j = 1; j <= len2; j++)
        dp[0][j] = j;
    
    for (i = 1; i <= len1; i++) {
        for (j = 1; j <= len2; j++) {
            if (s1[i-1] == s2[j-1]) {
                dp[i][j] = dp[i-1][j-1];
            }
            else {
                dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1;
            }
        }
    }
    return dp[len1][len2];
}

int main(void)
{
	string s;
	map<string, int> logs;
	map<string, int>::iterator map_it;
	int distance;
	int flag;
	int count;

	while (getline(cin, s)) {
		if (s.length()) {
			flag = 0;
			map_it = logs.begin();
			while (map_it != logs.end()) {
				distance = edit_distance(s, (map_it->first));
				if (distance <= 5) {
					map_it->second++;
					flag = 1;
				}
				++map_it;
			}
			if (!flag) {
				logs.insert(make_pair(s, 1));
			}
		}
		else
			break;
	}

	count = 0;
	map_it = logs.begin();
	while (map_it != logs.end()) {
		if (count < map_it->second) {
			count = map_it->second;
		}
		++map_it;
	}
	cout << count << endl;
	return 0;
}

PS:本人未参加微软在线测试,题目来源于贴吧,程序未经提交,不保证能够通过运行,对于题目解答有疑问或者有更好的解答,欢迎讨论。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值