查找两个字符串a,b中的最长公共子串,两种排序方法,求最小公倍数

问答题

问答题1:以下程序统计给定输入中每个大写字母的出现次数

void AlphabetCounting(char a[], int n) {
	int count[26] = {}, i, kind = 0;
	for (i = 0; i < n; ++i){
		// pass 1
	}
	for (i = 0; i < 26; ++i) {
		if (++kind > 1) putchar(';');
		printf("%c=%d",'Z'-i,count[i]);
	}
}

提示:第一个循环是一个计数,但是数组只能容纳26大小的字符,对于A-Z的ASCII码值过大,所以需要 Z-a[i] 进行计算.

答案:pass1 为: ++count['Z'-a[i]];

问答题2:请找出下面程序中有哪些错误?

int main(){
	int i=10;
	int j=1;
	const int *p1;//(1)
	int const *p2=&i; //(2)
	p2=&j;//(3)
	int *const p3=&i;//(4)
	*p3=20;//(5)
	*p2=30;//(6)
	p3=&j;//(7)
	return 0;
}

提示:const int * p1 = &i; 表示 p1 指向了 i 的地址,它的地址值不可改变,和 int const * p1 = &i 的意思一样,而 int * const p1 = &i;的意思是指针 p1 的指向不可改变.

答案:(6),(7)

问答题3:假定有类AB,有相应的构造函数定义,能正确执行
AB a(4),b(5),c[3],*p[2]={&a,&b};语句,请问执行完此语句后共调用该类的构造函数次数为?

提示:a,b 为有参构造,c为三次的无参数构造,对于指针数组只是进行定义指向一个地址而已,并没有 new 出来一个对象,所以不进行内存的分配,因此没有发生构造.

问答题4:有如下程序,执行后输出的结果是?

#include 
class cla{
public:
	cla(){n++;}
	~cla(){n--;}
	static int get_n(){
		return n;
	}
private:
	static int n;
};
int cla::n= 0;
int main(){
	cla *p =new cla;
	delete p;
	cout<<"n="<<cla::get_n()<<endl;
	return 0;
}

提示:对于指针没有new对象,那就不进行构造,所以n的值仍然为0

答案:n=0

问答题5:以下程序输出结果是?

class A{
public:
	A ():m_iVal(0){
		test();
	}
	virtual void func() {
		std::cout<<m_iVal<<‘ ’;
	}
	void test(){
		func();
	}
public:
	int m_iVal;
};
class B : public A{
public:
	B(){
		test();
	}
	virtual void func(){
		++m_iVal;
		std::cout<<m_iVal<<‘ ’;
	}
};
int main(int argc ,char* argv[]){
	A*p = new B;
	p->test();
	return 0;
}

提示:在 main 函数中,new 出一个B对象,先调用基类的构造函数,输出 m_iVal = 0;然后调用派生类的构造函数,里面有函数 test ,虽然B类中没有 test 函数,但是由于继承关系,类A中的 test 继承到B中,在 test 还有一个函数 fun,这时候会调用基类中的 fun 函数.

由于基类的指针p指向了子类对象,所以指针调用 test 会调用子类的 test,然后又会对 m_iVal ++ 操作,所以输出 2

答案:0 1 2

编程题

编程题1:汽水瓶

有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水

小张手上有十个空汽水瓶,她最多可以换5瓶汽水喝?

方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?

输入描述:输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数 n(1<=n<=100),表示小张手上的空汽水瓶数。n=0表示输入结束,你的程序不应当处理这一行

输出描述:对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数,如果一瓶也喝不到,输出 0

输入
3
10
81
0
输出
1
5
40

#include
#include
using namespace std;

int calculateNum(int num){
    int sum = 0;
    while (num > 1){
        int result = num / 3;
        int reminder = num % 3;
        sum = sum + result;
        num = result + reminder;
        if (num == 2){
            ++sum;
            break;
        }
    }
    return sum;
}

int main(){
    int n;
    while(cin>>n){
        cout<<calculateNum(n)<<endl;
    }
    return 0;
}

编程题2:查找两个字符串a,b中的最长公共子串

查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个

输入描述:输入两个字符串
输出描述:返回重复出现的字符

输入
a b c d e f g h i j k l m n o p
a b c s a f j k l m n o p q r s t u v w
输出
j k l m n o p

提示:动态规划

dp[i][j]记录短字符串 s1 前 i 个字符和长字符串 s2 前 j 个字符的最长子串的长度,初始化所有值为 0

s1[i-1] == s2[j-1]时,dp[i][j] = dp[i - 1][j - 1] + 1,这里使用一个额外的值,start 来记录最长子串在短字符串 s1 中出现的起始位置,max 记录当前最长子串的长度

#include 
#include 
#include 
using namespace std;

int main(){
    string str1,str2;
    while(cin>>str1>>str2){
    if(str1.size()>str2.size()){
        swap(str1,str2);
    }
    int max=0,start=0;
    vector<vector<int>>dp(str1.size()+1,\
                vector<int>(str2.size()+1,0));
    
    for(int i = 1;i<str1.size()+1;++i){
        for(int j = 1;j<str2.size()+1;++j){
            if(str1[i-1]==str2[j-1]){
                dp[i][j] = dp[i-1][j-1]+1;
            }
            if(dp[i][j]>max){
                max = dp[i][j];
                start = i-max;
            }
        }
    }
    cout<<str1.substr(start,max)<<endl;
    }
    return 0;
}

编程题3: 两种排序方法

考拉有n个字符串字符串,任意两个字符串长度都是不同的。考拉最近学习到有两种字符串的排序方法:

根据字符串的字典序排序
“car” < “carriage” < “cats” <"doggies < “koala”

据字符串的长度排序
“car” < “cats” < “koala” <“doggies” < “carriage”

考拉想知道自己的这些字符串排列顺序是否满足这两种排序方法,考拉要忙着吃树叶,所以需要你来帮忙验证

输入描述:输入第一行为字符串个数n(n ≤ 100)接下来的n行,每行一个字符串,字符串长度均小于100,均由小写字母组成

输出描述:如果这些字符串是根据字典序排列而不是根据长度排列输出"lexicographically",如果根据长度排列而不是字典序排列输出"lengths",如果两种方式都符合输出"both",否则输出"none"

例,输入 :3 a aa bbb 输出 :both

提示 把字符串放到容器 vector 中,然后分别按照两种方法进行比较;字典序的比较方式可以直接比较大小,长度按照字符串.size() 函数比较

#include 
#include 
using namespace std;

int main(){
    int n;
    while(cin>>n){
        vector<string>v(n);
        for(int i=0;i<n;++i){
            cin>>v[i];
        }
        // 判断是否满足字典序
        int dicsort = 1;
        for(int i=1;i<n;++i){
            if(v[i-1] > v[i]){
                dicsort = 0;
                break;
            }
        }
        // 判断是否满足长度排序
        int sizesort = 1;
        for(int i=1;i<n;++i){
            if(v[i-1].size() > v[i].size()){
                sizesort = 0;
                break;
            }
        }
        if(dicsort==1 && sizesort==1){
            cout<<"both"<<endl;
        }
        if(dicsort == 1 && sizesort ==0){
            cout<<"lexicographically"<<endl;
        }
        if(sizesort == 1 && dicsort == 0){
            cout<<"lengths"<<endl;
        }
        if (sizesort == 0 && dicsort ==0){
            cout<<"none"<<endl;
        }
    }
    return 0;
}

编程题4:求最小公倍数

正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数

输入描述:输入两个正整数A和B
输出描述:输出A和B的最小公倍数

例:输入:5 7 输出:35

方法一:暴力法,找到比较大的那个数,然后一直进行 前置++操作,直到可以被两个数字整除为止

#include 
using namespace std;

int main(){
    int A;
    int B;
    cin>>A;
    cin>>B;
    if(A>B){
        int temp = A;
        A = B;
        B = temp;
    }
    
    for(int i = B;i<=A*B;++i){
        if(i%A==0 && i%B ==0){
            cout<<i;
            break;
        }
    }
    return 0;
}

方法二:利用辗转相除法(循环),求出最大公约数,那么最小公倍数 == 两数积 / 最大公约数

例:15 和 20 ,他们的积为 300 ,他们最大公约数为 5 ,所以最小公倍数为 300/5 = 60

#include
using namespace std;

int gcd(int a, int b){
	int r = 0;
	while (r = a % b) {
		a = b;
		b = r;
	}
	return b;
}

int main(){
	int a, b;
	while (cin >> a >> b) {
		cout << a * b / gcd(a, b) << endl;
	}
	return 0;
}

方法三:利用辗转相除法(递归)

#include 
using namespace std;

int gcd(int a,int b){
    if(b==0){
        return a;
    }
     return gcd(b,a%b);
}
int main(){
    int a,b;
    while(cin>>a>>b){
        cout<<a*b/gcd(a,b)<<endl;
    }
    return 0;
}

你可能感兴趣的:(C++习题练习)