问答题
问答题1:简述一下什么是动态联编?
动态联编就是程序在运行的时候知道该调用哪个函数,而不是编译阶段,所以这个机制应该是由虚函数支持的,即运行时的多态,基类的某个成员函数声明为虚函数,派生类继承,而且同样重写该函数,那么当声明一个派生类的指针或者引用时,它所调用的函数是由该指针指向的对象确定的,这就是动态联编
问答题2:1. 若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用哪个存储方式最节省时间?
(A) 顺序表
(B) 双链表
(C) 带头结点的双循环链表
(D) 单循环链表
提示:插入和删除是在结尾的,所以利用顺序表也可以达到O(1)时间复杂度,另外还要进行任意位置的存取,所以选用顺序表
问答题3:下列数据结构具有记忆功能的是?
(A) 队列
(B) 循环队列
(C) 栈
(D) 顺序表
提示:可以用浏览网页的情况来理解,我们在浏览第一个网页A,点网页里的一个标题,进入网页B,再在网页B里点击一个标题,进入网页C,这时连续按后退退回网页A,这说明浏览网页有记忆功能,栈的原理跟相似
问答题4:循环两列放在一维数组 A[0…M-1]
中,end1
指向队头元素,end2
指向队尾元素的后一个位置。假设队列两端均可进行入队和出队操作,队列中最多能容纳M-1
个元素,初始时为空,下列判断队空和队满的条件中,正确的是?
(A) 队空:end1==end2;
队满:end1==(end2+1) mod M
(B) 队空:end1==end2;
队满:end2==(end1+1) mod (M-1)
(C) 队空:end2==(end1+1) mod M
队满:end1==(end2+1)mod M
(D) 队空:end1==(end2+1)mod M;
队满:end2==(end1+1) mod (M-1)
提示:队尾指针是rear,队头是front,其中QueueSize为循环队列的最大长度
队空条件:rear == front
队满条件:(rear+1) % QueueSIze == front
计算队列长度:(rear-front+QueueSize)% QueueSize
入队:(rear+1)% QueueSize
出队:(front+1)% QueueSize
编程题
编程题1:杨辉三角的变形
以下三角形的数阵,第一行只有一个数1,以下每行的每个数,是恰好是它上面的数,左上角数到右上角的数,3个数之和(如果不存在某个数,认为该数就是0)
求第n行第一个偶数出现的位置。如果没有偶数,则输出-1
输入描述:输入一个int整数;输出描述:输出返回的int值
示例1:输入:4;输出:3
解题思路:按照题目意思,可以发现第 n 行有 2n-1 个元素,第 i , j 元素等于上一行第 j-2 , j-1 , j 三列元素之和,每一行的第一列和最后一列都为 1,如果是第二列,则只是两个元素之和
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
int n, m;
while (cin >> n){
m = 2 * n - 1;
vector<vector<int>> dp(n, vector<int>(m, 0));
dp[0][0] = 1;
for (int i = 1; i < n; i++){
// 第一列和最后一列都为 1
dp[i][0] = dp[i][2 * i] = 1;
for (int j = 1; j < 2 * i; ++j){
if (j == 1) {
// 如果是第二列,则只是两个元素之和
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
}
else {
// 第 i,j 元素等于上一行第 j - 2,j - 1,j 三列元素之和
dp[i][j] = dp[i - 1][j - 2] + dp[i - 1][j - 1] + dp[i - 1][j];
}
}
}
int k;
for (k = 0; k < m; k++){
if (dp[n - 1][k] % 2 == 0 && dp[n - 1][k] != 0){
cout << k + 1 << endl;
break;
}
}
if (k == m)
cout << -1 << endl;
}
return 0;
}
编程题2:超长正整数的加法
输入描述:输入两个字符串数字
输出描述:输出相加后的结果,string型
输入:99999999999999999999999999999999999999999999999999 1
输出:100000000000000000000000000000000000000000000000000
方法一:利用进位
第一步:计算对应位的和,对应位相加 + 上一位的进位
第二步:更新当前位的值, 和 %10 ,把值转成字符(和-‘0’)存入字符结果中
第三步:更新进位, 和 / 10, 然后计算下一位的值
最后一步:如果计算完之后,进位为1,说明最高位产生了进位,所以需要再加一位,才是最后的结果。结果产生之后,需要逆置,得到最终结果
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
string addStrings(string num1, string num2) {
// 由低位向高位相加
int i = num1.size() - 1;
int j = num2.size() - 1;
string result = "";
//当前位的相加结果
int carry = 0;
while (i >= 0 || j >= 0){
if (i >= 0) {
carry += num1[i] - '0';
}
if (j >= 0) {
carry += num2[j] - '0';
}
// 当前为的最大值不大于 10
result += (char)(carry % 10 + '0');
//如果大于10,向上进一位
carry /= 10;
i--;
j--;
}
// 相加完之后,如果还有进位,则再加 1
if (carry == 1){
result += '1';
}
// 整体逆置
reverse(result.begin(), result.end());
return result;
}
int main(){
string s1, s2;
while (cin >> s1 >> s2){
cout << addStrings(s1, s2) << endl;
}
return 0;
}
方法二:首先将两个字符串补齐,前面补字符0,然后进行取余的取模的运算
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string multi_string(string str1,string str2){
int carry = 0,temp = 0;
while(str1.size()<str2.size()){
str1 = "0"+str1;
}
while(str1.size()>str2.size()){
str2= "0"+str2;
}
string res;
for(int i=str1.size()-1;i>=0;--i){
temp = str1[i]-'0' + str2[i]-'0'+carry;
res += temp%10 + '0';
if(temp/10){
carry = 1;
}else{
carry = 0;
}
}
if(carry==1){
res = "1"+res;
}
reverse(res.begin(),res.end());
return res;
}
int main(){
string str1,str2;
while(cin>>str1>>str2){
cout<<multi_string(str1,str2)<<endl;
}
return 0;
}