【牛客网】2017腾讯实习生编程题

一、构造回文

给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。

输入描述:

输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.



输出描述:

对于每组数据,输出一个整数,代表最少需要删除的字符个数。


输入例子:
abcda
google

输出例子:
2
2

思路:

根据回文串的特点,如果一个字符串是回文串,那么这个字符串和它的逆序串是相等的。所以上述问题转化为求字符串和逆序字符串的最长公共子序列长度。



c++代码:

#include<iostream>  
#include<cmath>  
#include<algorithm>  
using namespace std;  
int main(){  
    string s;  
    while(cin>>s){  
              
            string s1=s;  
            string s2=s;  
            reverse(s2.begin(),s2.end());  
            int len1=s1.length();  
            int len2=s2.length();  
              
            //动态申请一个二维数组  
            //因为题目给出了s.length<=1000,因此L的长度可以固定  
            //直接定义L[1001][1001]也可以,比动态规划更方便   
            int **L = new int* [len1+1];  
            int i,j;  
            for(i=0; i<=len1;i++){  
                L[i] = new int[len2+1];  
            }   
            for(i=0;i<=len1;i++){  
                for(j=0;j<=len2;j++)  
                    L[i][j]=0;  //对数组进行初始化   
            }//for  
              
            for(i=1;i<=len1;i++){  
                for(j=1;j<=len2;j++){  
                    if(s1[i-1] == s2[j-1]){  
                        L[i][j] = L[i-1][j-1] + 1;  
                    }else{  
                        L[i][j] = max(L[i-1][j], L[i][j-1]);  
                    }  
                }  
            }  
              
            cout<<len1-L[len1][len2]<<endl;  
    }  
      
  
      
    return 0;  
      
}  


二、算法基础-字符移位

小Q最近遇到了一个难题:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
你能帮帮小Q吗?



输入描述:

输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.



输出描述:

对于每组数据,输出移位后的字符串。


输入例子:
AkleBiCeilD

输出例子:
kleieilABCD

思路:

遍历两遍字符串,第一遍输出所有的小写字母,第二遍输出所有的大写字母


c++代码

#include<iostream>
#include<cstring>
using namespace std;
int main(){
	string s;
	while(cin>>s){
		int len=s.length();
		int i,j;
		for(i=0;i<len;i++){
			if(s[i]<='z' && s[i]>='a')
				cout<<s[i];
		}
		for(i=0;i<len;i++){
			if(s[i]<='Z' && s[i]>='A')
				cout<<s[i];
			
		}
		cout<<endl;
	}//while
	return 0;
	
}


三、有趣的数字

小Q今天在上厕所时想到了这个问题:有n个数,两两组成二元组,差最小的有多少对呢?差最大呢?



输入描述:

输入包含多组测试数据。 对于每组测试数据: N - 本组测试数据有n个数 a1,a2...an - 需要计算的数据 保证: 1<=N<=100000,0<=ai<=INT_MAX.



输出描述:

对于每组数据,输出两个数,第一个数表示差最小的对数,第二个数表示差最大的对数。


输入例子:
6
45 12 45 32 5 6

输出例子:
1 2

思路:

本题坑较多,题目提供的测试用例是远远不够的,好几种情况没想到也导致了我提交了很多次也没有AC。首先应该用map存储所有的数,first存储值,second存储这个数出现的次数。因为map自带first排序功能,因此从map.begin()开始往后遍历是first的值本来就是递增的,这让我们省掉了排序这一步。很显然,最大的差值肯定是第一个数减去最后一个数再取绝对值,第一个坑来了,如果所有的数都是一样的呢,比如总共3个数,分别是1 1 1,那么最小的差和最大的差是一样的,对数也是一样的。这种情况一定要考虑到。显然判断一下第一个数和最后一个数是否相同即可,若相同差最大的对数就等于差最小的对数就好。如果不相同再另算,对于两个数num1,num2,num1有a个,num2有b个,那么对数一共是(a*b)个。

现在要算差最小的对数,如果序列中有一个数出现的次数大于1次的,那么最小的差就是0,该数有n个,那么对数就是(n-1)*n/2个。注意第二个坑来了,一定不要忽略序列中有多个出现次数大于1次的数,所以在算对数的时候要把这些都加起来。

如果序列中所有的数都只出现了一次,那么最小的差肯定出现在相邻的两个数间。第三个坑来了,这样的对数不只是在一个相邻的两个数,其他相邻的两个数差也可能是最小的差,也一定要加上这种情况。


c++代码:

#include<iostream>
#include<map>
#include<climits>
#include<cmath>
using namespace std;

int main(){
	//用map来存储输入,first存值,second存出现的次数
	
	int n;  //有n个数
	while(cin>>n){
		map<int, int> a;
		int tmp,i,j;
		int flag=0;
		for(i=0;i<n;i++){
			cin>>tmp;
			if(a[tmp]>1)
				flag=1;
			a[tmp] ++;
		}
		
		
		map<int,int>::iterator it1;
		map<int,int>::iterator it2;

		int min=INT_MAX;
		int min_count=0;
		int max_count=0;
		it1 = a.begin();
		it2 = a.begin();
		it2++;	
		if(flag){
			int count;
			for(it1=a.begin();it1!=a.end();it1++){
				count = it1->second;
				if(count > 1){
					tmp = ((count-1)*count)/2;
					min_count += tmp;
				}
			}
		}else{
			//相隔的 
			for(;it2!=a.end();it1++,it2++){
				tmp = fabs((it1->first) - (it2->first));
				if(tmp<min){
					min=tmp;
					min_count = (it1->second) * (it2->second);
				}else if(tmp == min){
					min_count++;
				}
			}//for
		}

		it1=a.begin();
		it2=a.end(); 
		it2--;
		if(it1->first == it2->first)
			max_count=min_count;
		else
			max_count = (it1->second)*(it2->second);
		cout<<min_count<<" "<<max_count<<endl;
		
	} //while
	return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值