查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。(与上一节题目7相似,利用动态规划)
#include
#include
using namespace std;
int main(){
string str1, str2;
while (cin >> str1 ){
cin >> str2;
if (str1.size() > str2.size())
swap(str1,str2);
int length1 = str1.size();
int length2 = str2.size();
int matrix[length1+1][length2+1];
memset(matrix, 0, sizeof(matrix));
int max = 0, maxRow = 0;
for (int i = 1; i <= length1; i++){
for (int j = 1; j <= length2; j++){
if (str1[i-1] == str2[j-1])
matrix[i][j] = matrix[i-1][j-1] + 1;
if (matrix[i][j] > max){
max = matrix[i][j];
maxRow = i;
}
}
}
cout << str1.substr(maxRow-max,max) << endl;
}
}
计算整数二进制中1的个数。(使用位运算)
#include
using namespace std;
int main(){
int n;
while(cin >> n){
int count = 0;
while (n){
count++;
n = n & (n-1);
}
cout << count << endl;
}
}
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。
给定函数count(int n),用于计算n以内(含n)完全数的个数。计算范围, 0 < n <= 500000。返回n以内完全数的个数。 异常情况返回-1
#include
using namespace std;
bool isPrefect(int n){
int sum = 0;
for (int i = 1; i < n; i++){
if (n % i == 0)
sum += i;
}
if (sum == n)
return true;
else
return false;
}
int main(){
int n;
while (cin >> n){
if (n <= 0 || n>= 500000)
cout << -1 << endl;
else{
int count = 0;
for (int i = 1; i <= n; i++){
if (isPrefect(i))
count++;
}
cout << count << endl;
}
}
}
求杨辉三角形的第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3。
#include
#include
using namespace std;
int main(){
int n;
while (cin >> n){
int m = 2 * n - 1;
int matrix[n][m];
memset(matrix,0,sizeof(matrix));
matrix[0][n-1] = 1;
for (int i = 1; i < n; i++){
for (int j = 1; j < m; j++){//对第n行,第一个数为1,所以从第二个数考虑的,比较方便
matrix[i][j] = matrix[i-1][j-1] + matrix[i-1][j] + matrix[i-1][j+1];
}
}
for (int k = 1; k < n; k++){
if (matrix[n-1][k] % 2 == 0){
cout << k+1 << endl;
break;
}
}
}
return 0;
}
有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问每个月的兔子总数为多少?(讨论一月大、二月大、三月大的兔子有多少只)
#include
using namespace std;
int main(){
int n;
while(cin >> n){
int oneMonth = 1, twoMonth = 0, threeMonth = 0;
for (int i = 2; i <= n; i++){
threeMonth += twoMonth;
twoMonth = oneMonth;
oneMonth = threeMonth;
}
cout << oneMonth + twoMonth + threeMonth << endl;
}
}
有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝
#include
using namespace std;
int main(){
int n;
while (cin >> n){
if (n == 0)
return 0;
int drinkCount = 0;
while (n > 2){
drinkCount += n / 3;//喝的数量
n = n / 3 + n % 3;//空瓶数量
}
if (n == 2)
drinkCount++;
cout << drinkCount << endl;
}
return 0;
}
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
#include
#include
using namespace std;
int main(){
string str;
while (cin >> str){
int length = str.size();
string reversedStr;
for (int i = 1; i <= length; i++)
reversedStr.push_back(str[length-i]);
cout << reversedStr << endl;
}
}
输入一个整数,将这个整数以字符串的形式逆序输出。
#include
using namespace std;
int main(){
int n;
while(cin >> n){
while (n != 0){
cout << n % 10;
n = n / 10;
}
cout << endl;
}
}
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A、2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用"-“连接,每手牌的每张牌以空格分隔,”-"两边没有空格,如:4 4 4 4-joker JOKER。
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR。
基本规则:
(1)输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子);
(3)大小规则跟大家平时了解的常见规则相同,个子、对子、三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
(4)输入的两手牌不会出现相等的情况。
要点:取左右手牌的第一张牌的时候,不能直接取第一个字符,而是要取第一个空格前的所有字符,如10.为了方便比较牌的大小,将字符转化为数字。
#include
#include
#include
using namespace std;
int main(){
map<string,int> m;
m["3"] = 3; m["4"] = 4; m["5"] = 5; m["6"] = 6; m["7"] = 7;m["8"] = 8; m["9"] = 9;
m["10"] = 10; m["J"] = 11; m["Q"] = 12; m["K"] = 13; m["A"] = 14; m["2"] = 15;
string poker;
while (getline(cin,poker)){
int pos = poker.find('-');
string leftPoker = poker.substr(0,pos);
string rightPoker = poker.substr(pos+1);
int leftCount = 0, rightCount = 0;//计算两手牌的数量
for (int i = 0; i < leftPoker.size(); i++){
if (leftPoker[i] == ' ')
leftCount++;
}
leftCount++;
for (int i = 0; i < rightPoker.size(); i++){
if (rightPoker[i] == ' ')
rightCount++;
}
rightCount++;
string leftPokerFirst = leftPoker.substr(0,leftPoker.find(' '));
string rightPokerFirst = rightPoker.substr(0,rightPoker.find(' '));
string result;
if (leftPoker == "joker JOKER" || rightPoker == "joker JOKER"){//一方有王炸
result = "joker JOKER";
}
else if (leftCount == 4 || rightCount == 4){//一方有炸弹
if (leftCount == 4 && rightCount == 4)
result = m[leftPokerFirst] < m[rightPokerFirst] ? rightPoker : leftPoker;
else if (leftCount == 4)
result = leftPoker;
else
result = rightPoker;
}
else if (leftCount == rightCount){
result = m[leftPokerFirst] < m[rightPokerFirst] ? rightPoker : leftPoker;
}
else
result = "ERROR";
cout << result << endl;
}
}
对于不同的字符串,我们希望能有办法判断相似程度,我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法如下:
1 修改一个字符,如把“a”替换为“b”。
2 增加一个字符,如把“abdd”变为“aebdd”。
3 删除一个字符,如把“travelling”变为“traveling”。
比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加和减少一个“g”的方式来达到目的。上面的两种方案,都只需要一次操作。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于“距离+1”的倒数。也就是说,“abcdefg”和“abcdef”的距离为1,相似度为1/2=0.5.
给定任意两个字符串,你是否能写出一个算法来计算出它们的相似度呢?
解题方法:使用动态规划。假设第一个字符串str1长度为M,第二个字符串str2长度为N。
1.求解状态转移矩阵 d p [ M + 1 ] [ N + 1 ] dp[M + 1][N + 1] dp[M+1][N+1], d p [ i ] [ j ] dp[i][j] dp[i][j] 的值代表的是将str1的前i个字符str1[0…i-1]编辑为str2的前j个字符str2[0…j-1]
的最小代价。
2. 计算过程:
1) d p [ 0 ] [ 0 ] = 0 dp[0][0] = 0 dp[0][0]=0,表示str1空的字串编辑为str2空的字串代价为0。
2)矩阵dp第一列即为 d p [ 0... M − 1 ] [ 0 ] dp[0...M-1][0] dp[0...M−1][0], d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示str1[0…i-1]编辑为空串的最小代价,所以就是将str1[0…M-1]的字符删掉的代价, 所以dp[i][0] = i;
3) 同2),那str2[0…j-1]编辑的代价,dp[0][j] = j;
4) 接下来的位置就按照从左到右,从上到下来计算,dp[i][j]的值来至于下面的几种情况:
(1) 删除:将 s t r 1 [ 0.. i − 2 str1[0..i-2 str1[0..i−2]编辑为 s t r 2 [ 0... j − 1 ] str2[0...j-1] str2[0...j−1],然后删除字符 s t r 1 [ i − 1 ] , d p [ i − 1 ] [ j ] str1[i-1], dp[i-1][j] str1[i−1],dp[i−1][j]表示 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i−2]编辑为s t r 2 [ 0... j − 1 ] tr2[0...j-1] tr2[0...j−1]的最小代价,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]可能等于 d p [ i − 1 ] [ j ] + 1 dp[i -1][j] + 1 dp[i−1][j]+1;
(2)插入:将 s t r 1 [ 0... i − 1 ] str1[0...i-1] str1[0...i−1]可以先编辑为 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j−2],然后将 s t r 2 [ j − 1 ] str2[j-1] str2[j−1]插入到 s t r 1 [ i − 1 ] str1[i-1] str1[i−1]和 s t r 1 [ i ] str1[i] str1[i]之间, d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1]表示 s t r 1 [ 0.. i − 1 ] str1[0..i-1] str1[0..i−1]编辑成 s t r 2 [ 0... j − 2 ] str2[0...j-2] str2[0...j−2]的最小代价,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]可能等于 d p [ i ] [ j − 1 ] + 1 dp[i][j-1] + 1 dp[i][j−1]+1;
(3) 如果 s t r 1 [ i − 1 ] ! = s t r 2 [ j − 1 ] str1[i - 1]!=str2[j-1] str1[i−1]!=str2[j−1],那么先把 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i−2]编辑成 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j−2],然后把字符 s t r 1 [ i − 1 ] str1[i-1] str1[i−1]替换为 s t r 2 [ j − 1 ] str2[j-1] str2[j−1],这样 s t r 1 [ 0.. i − 1 ] str1[0..i-1] str1[0..i−1]就编辑成为 s t r 2 [ 0... j − 1 ] str2[0...j-1] str2[0...j−1]了, d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i−1][j−1]表示 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i−2]编辑为 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j−2]的最小代价,那么 d p [ i ] [ j ] dp[i ][j] dp[i][j]可能等于 d p [ i − 1 ] [ j − 1 ] + 1 dp[i - 1][j - 1] + 1 dp[i−1][j−1]+1;
(4) 如果 s t r 1 [ i − 1 ] = = s t r 2 [ j − 1 ] str1[i - 1]==str2[j-1] str1[i−1]==str2[j−1] ,那么先把 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i−2]编辑成 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j−2],因为此时 s t r 1 [ i − 1 ] = = s t r 2 [ j − 1 ] str1[i - 1]==str2[j-1] str1[i−1]==str2[j−1] ,所以 s t r 1 [ 0.. i − 1 ] 已 经 编 辑 为 s t r 2 [ 0.. j − 1 ] str1[0..i-1]已经编辑为str2[0..j-1] str1[0..i−1]已经编辑为str2[0..j−1]了, d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i−1][j−1]表示 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i−2]编辑为 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j−2]的最小代价, 那么 p [ i ] [ j ] p[i ][j] p[i][j]可能等于 d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i−1][j−1]。
上述的4中情况取最小值,dp的最右下角就是最终结果,即最小编辑代价。
#include
#include
#include
using namespace std;
int main(){
string str1, str2;
while (cin >> str1 >> str2){
int length1 = str1.size();
int length2 = str2.size();
int dpMatrix[length1+1][length2+1];
memset(dpMatrix,0,sizeof(dpMatrix));
for(int i = 1; i <= length1; i++)
dpMatrix[i][0] = i;
for (int j = 1; j <= length2; j++)
dpMatrix[0][j] = j;
for (int i = 1; i <= length1; i++){
for (int j = 1; j <= length2; j++){
int caseOne = dpMatrix[i-1][j] + 1;
int caseTwo = dpMatrix[i][j-1] + 1;
int caseThree = 0;
if (str1[i-1] == str2[j-1])
caseThree = dpMatrix[i-1][j-1];
else
caseThree = dpMatrix[i-1][j-1] + 1;
dpMatrix[i][j] = min(caseOne,min(caseTwo,caseThree));
}
}
cout << 1 << "/" << (dpMatrix[length1][length2] + 1) << endl;
}
}