算法设计与分析(李春保)练习题答案v1
1.1第1 章─概论
1.1.1练习题
1.下列关于算法的说法中正确的有()。
Ⅰ.求解某一类问题的算法是唯一的
Ⅱ.算法必须在有限步操作之后停止
Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊
Ⅳ.算法执行后一定产生确定的结果
A. 1 个B.2 个C.3 个D.4 个
2. T(n)表示当输入规模为n时的算法效率,以下算法效率最优的是()。
A.T(n)= T(n-1)+1,T(1)=1 C.T(n)= T(n/2)+1,T(1)=1
B.T(n)= 2n
D.T(n)=3nlog2n
3.什么是算法?算法有哪些特征?
4.判断一个大于2的正整数n是否为素数的方法有多种,给出两种算法,说明其中一种算法更好的理由。
5.证明以下关系成立:
(1)10n-2n=(n)
(2)2=(2)
6.证明O(f(n))+O(g(n))=O(max{f(n),g(n)})。
7.有一个含n(n>2)个整数的数组a,判断其中是否存在出现次数超过所有元素一半的元素。
8.一个字符串采用string 对象存储,设计一个算法判断该字符串是否为回文。
9.有一个整数序列,设计一个算法判断其中是否存在两个元素和恰好等于给定的整数k。
10.有两个整数序列,每个整数序列中所有元素均不相同。设计一个算法求它们的公共元素,要求不使用STL 的集合算法。
11.正整数n(n>1)可以写成质数的乘积形式,称为整数的质因数分解。例如,12=2*2*3,18=2*3*3,11=11。设计一个算法求n这样分解后各个质因数出现的次数,采用vector 向量存放结果。
12.有一个整数序列,所有元素均不相同,设计一个算法求相差最小的元素对的个数。如序列4、1、2、3的相差最小的元素对的个数是3,其元素对是(1,2),(2,3),(3,4)。
13.有一个map<string,int>容器,其中已经存放了较多元素。设计一个算法求出其中重复的value 并且返回重复value 的个数。
14.重新做第10题,采用map 容器存放最终结果。
15.假设有一个含n(n>1)个元素的stack<int>栈容器st,设计一个算法出栈从栈顶到栈底的第k(1≤k≤n)个元素,其他栈元素不变。
算法设计
1.1.2练习题参考答案
1.答:由于算法具有有穷性、确定性和输出性,因而Ⅱ、Ⅲ、Ⅳ正确,而解决某一类问题的算法不一定是唯一的。答案为C。
2.答:选项A的时间复杂度为O(n)。选项B的时间复杂度为O(n)。选项C的时间复杂度为O(log2n)。选项D 的时间复杂度为O(nlog2n)。答案为C。
3.答:算法是求解问题的一系列计算步骤。算法具有有限性、确定性、可行性、输入性和输出性5 个重要特征。
4.答:两种算法如下:
#include <stdio.h>
#include <math.h>
boolisPrime1(intn)//方法1
{for (int i=2;i<n;i++)
if (n%i==0)
return false;
return true;
}
boolisPrime2(intn)//方法2
{for (int i=2;i<=(int)sqrt(n);i++)
if (n%i==0)
return false;
return true;
}
voidmain()
{int n=5;
printf("%d,%d\n",isPrime1(n),isPrime2(n));
}
方法1 的时间复杂度为O(n),方法2的时间复杂度为n,所以方法2 更好。5.答:(1)当n 足够大时,(10n-2n)/( n)=10,所以10n-2n=(n)。
(2)2=2*2=(2)。
6.证明:对于任意f1(n)∈O(f(n)),存在正常数c1 和正常数n1,使得对所有n≥n1,有f1(n)≤c1f(n)。
类似地,对于任意g1(n)∈O(g(n)),存在正常数c2 和自然数n2,使得对所有n≥n2,有g1(n)≤c2g(n)。
令c3=max{c1,c2},n3=max{n1,n2},h(n)= max{f(n),g(n)}。
则对所有的n≥n3,有:
f1(n) +g1(n)≤c1f(n) +c2g(n)≤c3f(n)+c3g(n)=c3(f(n)+g(n))
≤c32max{f(n),g(n)}=2c3h(n)=O(max{f(n),g(n)})。
7.解:先将a 中元素递增排序,再求出现次数最多的次数maxnum,最后判断是否满足条件。对应的程序如下:
#include <stdio.h>
#include <algorithm>
using namespace std;
2
第1章
概论
boolsolve(inta[],intn,int&x)
{sort(a,a+n);
int maxnum=0;
int num=1;
int e=a[0];
for (int i=1;i<n;i++)
{if (a[i]==e)
{num++;
//递增排序
//出现次数最多的次数
if (num>maxnum)
{maxnum=num;
x=e;
}
}
else
{e=a[i];
num=1;
}
}
if (maxnum>n/2)
return true;
else
return false;
}
voidmain()
{int a[]={2,2,2,4,5,6,2};
int n=sizeof(a)/sizeof(a[0]);
int x;
if (solve(a,n,x))
printf("出现次数超过所有元素一半的元素为%d\n",x); else
printf("不存在出现次数超过所有元素一半的元素\n");
}
上述程序的执行结果如图1.1 所示。
图1.1
程序执行结果
8.解:采用前后字符判断方法,对应的程序如下:#include <iostream>
#include <string>
using namespace std;
boolsolve(stringstr)//判断字符串str是否为回文{int i=0,j=str.length()-1;
while (i<j)
{if (str[i]!=str[j])
return false;
3
算法设计
i++; j--;
}
return true;
}
voidmain()
{cout << "求解结果"<<endl;
string str="abcd";
cout << "" << str<<(solve(str)?"是回文":"不是回文")<< endl; string str1="abba";
cout << "" << str1<<(solve(str1)?"是回文":"不是回文")<<endl;}
上述程序的执行结果如图1.2所示。
图1.2
程序执行结果
9.解:先将a 中元素递增排序,然后从两端开始进行判断。对应的程序如下:#include <stdio.h>
#include <algorithm>
using namespace std;
boolsolve(inta[],intn,intk)
{sort(a,a+n);
int i=0, j=n-1;
while (i<j)
{if (a[i]+a[j]==k)
return true;
//递增排序
//区间中存在两个或者以上元素
else if (a[i]+a[j]<k)
i++;
else
j--;
}
return false;
}
voidmain()
{int a[]={1,2,4,5,3};
int n=sizeof(a)/sizeof(a[0]);
printf("求解结果\n");
int k=9,i,j;
if (solve(a,n,k,i,j))
printf("存在: %d+%d=%d\n",a[i],a[j],k);else
printf("不存在两个元素和为%d\n",k);
int k1=10;
if (solve(a,n,k1,i,j))
printf("存在: %d+%d=%d\n",a[i],a[j],k1);
4
第1章
概论
else
printf("
不存在两个元素和为%d\n",k1);
}
上述程序的执行结果如图1.3 所示。
图1.3
程序执行结果
10.解:采用集合set<int>存储整数序列,集合中元素默认是递增排序的,再采用二路归并算法求它们的交集。对应的程序如下:
#include <stdio.h>
#include <set>
using namespace std;
voidsolve(set<int>s1,set<int>s2,set<int>&s3){set<int>::iteratorit1,it2;
it1=s1.begin(); it2=s2.begin();
while (it1!=s1.end()&& it2!=s2.end())
{if (*it1==*it2)
{s3.insert(*it1);
++it1; ++it2;
}
else if (*it1<*it2)
++it1;
else
++it2;
}
}
//求交集s3
voiddispset(set<int>s)
{set<int>::iteratorit;
//输出集合的元素
for (it=s.begin();it!=s.end();++it)
printf("%d ",*it);
printf("\n");
}
voidmain()
{int a[]={3,2,4,8};
int n=sizeof(a)/sizeof(a[0]);
set<int> s1(a,a+n);
int b[]={1,2,4,5,3};
int m=sizeof(b)/sizeof(b[0]);
set<int> s2(b,b+m);
set<int> s3;
solve(s1,s2,s3);
printf("求解结果\n");
printf("s1: ");dispset(s1);
5
算法设计
printf("
printf("
s2: "); dispset(s2);
s3: "); dispset(s3);
}
上述程序的执行结果如图1.4 所示。
图1.4
程序执行结果
11.解:对于正整数n,从i=2 开始查找其质因数,ic 记录质因数i 出现的次数,当找到这样质因数后,将(i,ic)作为一个元素插入到vector 容器v 中。最后输出v。对应的算法如下:
#include <stdio.h>
#include <vector>
using namespace std;
struct NodeType
{int p;
int pc;
//vector向量元素类型 //质因数
//质因数出现次数
};
voidsolve(intn,vector<NodeType>&v)//求n的质因数分解{int i=2;
int ic=0;
NodeType e;
do
{if (n%i==0)
{ic++;
n=n/i;
}
else
{if (ic>0)
{e.p=i;
e.pc=ic;
v.push_back(e);
}
ic=0;
i++;
}
} while (n>1 || ic!=0);
}
voiddisp(vector<NodeType>&v)//输出v
{vector<NodeType>::iteratorit;
for (it=v.begin();it!=v.end();++it)
printf("质因数%d出现%d次\n",it->p,it->pc);
}
6
第1章
概论
voidmain()
{vector<NodeType>v;
int n=100;
printf("n=%d\n",n);
solve(n,v);
disp(v);
}
上述程序的执行结果如图1.5 所示。
图1.5
程序执行结果
12.解:先递增排序,再求相邻元素差,比较求最小元素差,累计最小元素差的个数。对应的程序如下:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
intsolve(vector<int>&myv)
//求myv中相差最小的元素对的个数
{sort(myv.begin(),myv.end());//递增排序
int ans=1;
int mindif=myv[1]-myv[0];
for (int i=2;i<myv.size();i++)
{if (myv[i]-myv[i-1]<mindif)
{ans=1;
mindif=myv[i]-myv[i-1];
}
else if (myv[i]-myv[i-1]==mindif)
ans++;
}
return ans;
}
voidmain()
{int a[]={4,1,2,3};
int n=sizeof(a)/sizeof(a[0]);
vector<int> myv(a,a+n);
cout << "相差最小的元素对的个数:" << solve(myv) <<endl; }
上述程序的执行结果如图1.6 所示。
7
图1.6
算法设计
程序执行结果
13.解:对于map<string,int>容器mymap,设计另外一个map<int,int>容器tmap,将前者的value 作为后者的关键字。遍历mymap,累计tmap 中相同关键字的次数。一个参考程序及其输出结果如下:
#include <iostream>
#include <map>
#include <string>
using namespace std;
voidmain()
{map<string,int>mymap;
mymap.insert(pair<string,int>("Mary",80));
mymap.insert(pair<string,int>("Smith",82));
mymap.insert(pair<string,int>("John",80));
mymap.insert(pair<string,int>("Lippman",95));
mymap.insert(pair<string,int>("Detial",82));
map<string,int>::iteratorit;
map<int,int> tmap;
for (it=mymap.begin();it!=mymap.end();it++)
tmap[(*it).second]++;
map<int,int>::iteratorit1;
cout << "求解结果"<<endl;
for (it1=tmap.begin();it1!=tmap.end();it1++)
cout << "" << (*it1).first<< ":" << (*it1).second<< "次\n";
}
上述程序的执行结果如图1.7 所示。
图1.7
程序执行结果
14.解:采用map<int,int>容器mymap 存放求解结果,第一个分量存放质因数,第二个分量存放质因数出现次数。对应的程序如下:
#include <stdio.h>
#include <map>
using namespace std;
voidsolve(intn,map<int,int>&mymap)//求n的质因数分解
{int i=2;
int ic=0;
do
{
if (n%i==0)
{ic++;
n=n/i;
}
8
第1章
概论
else
{if (ic>0)
mymap[i]=ic;
ic=0;
i++;
}
} while (n>1 || ic!=0);
}
voiddisp(map<int,int>&mymap)//输出mymap
{map<int,int>::iteratorit;
for (it=mymap.begin();it!=mymap.end();++it)
printf("质因数%d出现%d次\n",it->first,it->second);
}
voidmain()
{map<int,int>mymap;
int n=12345;
printf("n=%d\n",n);
solve(n,mymap);
disp(mymap);
}
上述程序的执行结果如图1.8 所示。
图1.8
程序执行结果
15.解:栈容器不能顺序遍历,为此创建一个临时tmpst 栈,将st 的k个元素出栈并进栈到tmpst 中,再出栈tmpst一次得到第k 个元素,最后将栈tmpst 的所有元素出栈并进栈到st 中。对应的程序如下:
#include <stdio.h>
#include <stack>
using namespace std;
intsolve(stack<int>&st,intk)
{stack<int> tmpst;
int e;
for (int i=0;i<k;i++)
{e=st.top();
st.pop();
tmpst.push(e);
}
e=tmpst.top();
tmpst.pop();
while (!tmpst.empty())
{st.push(tmpst.top());
tmpst.pop();
//出栈第k个元素
//出栈st的k个元素并进tmpst栈//求第k个元素
//将tmpst的所有元素出栈并进栈st9
}
return e;
}
voiddisp(stack<int>&st)
{while (!st.empty())
{printf("%d ",st.top());
st.pop();
}
printf("\n");
}
voidmain()
{stack<int> st;
算法设计
//出栈st的所有元素
printf("进栈元素1,2,3,4\n");st.push(1);
st.push(2);
st.push(3);
st.push(4);
int k=3;
int e=solve(st,k);
printf("出栈第%d个元素是: %d\n",k,e);printf("st中元素出栈顺序: "); disp(st);
}
上述程序的执行结果如图1.9 所示。
图1.9
程序执行结果
1.2第2 章─递归算法设计技术
1.2.1练习题
1.什么是直接递归和间接递归?消除递归一般要用到什么数据结构?2.分析以下程序的执行结果:
#include <stdio.h>
voidf(intn,int&m)
{if (n<1) return;
else
{
}
printf("调用f(%d,%d)前,n=%d,m=%d\n",n-1,m-1,n,m);n--; m--;
f(n-1,m);
printf("调用f(%d,%d)后:n=%d,m=%d\n",n-1,m-1,n,m);
10
第1章
概论
}
voidmain()
{int n=4,m=4;
f(n,m);
}
3.采用直接推导方法求解以下递归方程:T(1)=1
T(n)=T(n-1)+n当n>1
4.采用特征方程方法求解以下递归方程:H(0)=0
H(1)=1
H(2)=2
H(n)=H(n-1)+9H(n-2)-9H(n-3)当n>2 5.采用递归树方法求解以下递归方程:T(1)=1
T(n)=4T(n/2)+n当n>1
6.采用主方法求解以下题的递归方程。
T(n)=1
当n=1
T(n)=4T(n/2)+n当n>1
7.分析求斐波那契f(n)的时间复杂度。
8.数列的首项a1=0,后续奇数项和偶数项的计算公式分别为a2n=a2n-1+2,a2n+1=a2n- 1+a2n-1,写出计算数列第n项的递归算法。
9.对于一个采用字符数组存放的字符串str,设计一个递归算法求其字符个数(长度)。
10.对于一个采用字符数组存放的字符串str,设计一个递归算法判断str 是否为回文。
11.对于不带头结点的单链表L,设计一个递归算法正序输出所有结点值。
12.对于不带头结点的单链表L,设计一个递归算法逆序输出所有结点值。
13.对于不带头结点的非空单链表L,设计一个递归算法返回最大值结点的地址(假设这样的结点唯一)。
14.对于不带头结点的单链表L,设计一个递归算法返回第一个值为x 的结点的地址,没有这样的结点时返回NULL。
15.对于不带头结点的单链表L,设计一个递归算法删除第一个值为x 的结点。
16.假设二叉树采用二叉链存储结构存放,结点值为int 类型,设计一个递归算法求二叉树bt 中所有叶子结点值之和。
17.假设二叉树采用二叉链存储结构存放,结点值为int 类型,设计一个递归算法求二叉树bt 中所有结点值大于等于k 的结点个数。
18.假设二叉树采用二叉链存储结构存放,所有结点值均不相同,设计一个递归算法求值为x 的结点的层次(根结点的层次为1),没有找到这样的结点时返回0。
11
算法设计
1.2.2练习题参考答案
1.答:一个f 函数定义中直接调用f 函数自己,称为直接递归。一个f 函数定义中调用g 函数,而g 函数的定义中调用f 函数,称为间接递归。消除递归一般要用栈实现。
2.答:递归函数f(n,m)中,n是非引用参数,m是引用参数,所以递归函数的状态为(n)。程序执行结果如下:
调用f(3,3)前,n=4,m=4
调用f(1,2)前,n=2,m=3
调用f(0,1)后,n=1,m=2
调用f(2,1)后,n=3,m=2
3.解:求T(n)的过程如下:
T(n)=T(n-1)+n=[T(n-2)+n-1)]+n=T(n-2)+n+(n-1)
=T(n-3)+n+(n-1)+(n-2)
=…
=T(1)+n+(n-1)+…+2
=n+(n-1)+ +…+2+1=n(n+1)/2=O(n)。
4.解:整数一个常系数的线性齐次递推式,用x
n-33232
代替H(n),有:x=x+9x-9x,
x-x-9x+9=x(x-9)-(x-9)=(x-1)(x-9)=(x-1)(x+3)(x-3)=0。得到r1=1,r2=-3,r3=3则递归方程的通解为:H(n)=c1+c2(-3)+c33
代入H(0)=0,有c1+c2+c3=0
代入H(1)=1,有c1-3c2+3c3=1
代入H(2)=2,有c1+9c2+9c3=2
求出:c1=-1/4,c2=-1/12,c3=1/3,H(n)=c1+c2(-3)+c33=(
n‒1
4
+ 13
1
‒。
5.解:构造的递归树如图1.10 所示,第1 层的问题规模为n,第2 的层的子问题的问题规模为n/2,依此类推,当展开到第k+1层,其规模为n/2=1,所以递归树的高度为log2n+1。
第1层有1个结点,其时间为n,第2层有4个结点,其时间为4(n/2)=2n,依次类推,第k 层有4个结点,每个子问题规模为n/2,其时间为4(n/2)=2n。叶子结点的个数为n 个,其时间为n。将递归树每一层的时间加起来,可得:
logn
T(n)=n+2n+…+ 2n+…+n≈
算法设计与分析(李春保)练习题答案v1的更多相关文章
- 算法设计与分析(李春保)练习题答案v2
----------------------------------------------------- Page 1 --------------------------------------- ...
- 算法设计与分析 - AC 题目 - 第 5 弹(重复第 2 弹)
PTA-算法设计与分析-AC原题 - 最大子列和问题 (20分) 给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+, ..., Nj },其中 ≤i ...
- 算法设计与分析 - AC 题目 - 第 2 弹
PTA-算法设计与分析-AC原题7-1 最大子列和问题 (20分)给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1 ...
- 【技术文档】《算法设计与分析导论》R.C.T.Lee等·第7章 动态规划
由于种种原因(看这一章间隔的时间太长,弄不清动态规划.分治.递归是什么关系),导致这章内容看了三遍才基本看懂动态规划是什么.动态规划适合解决可分阶段的组合优化问题,但它又不同于贪心算法,动态规划所解决 ...
- 算法设计与分析-Week12
题目描述 You are given coins of different denominations and a total amount of money amount. Write a func ...
- 算法设计与分析 - 李春葆 - 第二版 - pdf->word v3
1.1 第1章─概论 练习题 . 下列关于算法的说法中正确的有( ). Ⅰ.求解某一类问题的算法是唯一的 Ⅱ.算法必须在有限步操作之后停止 Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊 Ⅳ. ...
- 算法设计与分析 - 李春葆 - 第二版 - html v2
1 .1 第 1 章─概论 1.1.1 练习题 1 . 下列关于算法的说法中正确的有( ). Ⅰ Ⅱ Ⅲ Ⅳ .求解某一类问题的算法是唯一的 .算法必须在有限步操作之后停止 .算法 ...
- 算法设计与分析 - 李春葆 - 第二版 - pdf->word v1
章─概论 练习题 . 下列关于算法的说法中正确的有( ).Ⅰ.求解某一类问题的算法是唯一的 Ⅱ.算法必须在有限步操作之后停止 Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊Ⅳ.算法执行后一定产 ...
- 南大算法设计与分析课程复习笔记(1) L1 - Model of computation
一.计算模型 1.1 定义: 我们在思考和处理算法的时候是机器无关.实现语言无关的.所有的算法运行在一种“抽象的机器”之上,这就是计算模型. 1.2 种类 图灵机是最有名的计算模型,本课使用更简单更合 ...
随机推荐
- QML MouseArea学习小结
QML中的MouseArea类型为用户进行简单的鼠标操作提供了方便. MouseArea是一个不可见的Item,通常与可见项目结合使用,以便为该项目提供鼠标处理.通过有效地充当代理,鼠标处理的逻辑可以 ...
- Atlassian JIRA服务器模板注入漏洞复现(CVE-2019-11581)
0x00 漏洞描述 Atlassian Jira是澳大利亚Atlassian公司的一套缺陷跟踪管理系统.该系统主要用于对工作中各类问题.缺陷进行跟踪管理. Atlassian Jira Server和 ...
- 简单几招提速 Kotlin Kapt编译
https://droidyue.com/blog/2019/08/18/faster-kapt/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_ ...
- SQOOP的使用方法
Sqoop是个命令行工具,用来在Hadoop和rdbms之间传输数据. 以Hadoop的角度看待数据流向,从rdbms往Hadoop是导入用sqoop import命令,反之从hadoop往rdbms ...
- AIX—日常运维命令总结
1. 查看AIX服务器的物理构造信息,包括服务器网络配置信息 # prtconf # ifconfig -a # lsattr -E -l mem0 :查看系统内存大小 # netstat -in : ...
- OpenSSL生成私钥和公钥
1.生成私钥 -- 生成 RSA 私钥(传统格式的) openssl genrsa -out rsa_private_key.pem 1024 -- 将传统格式的私钥转换成 PKCS#8 格式的(JA ...
- ChengDu University Mental Health Test 需求分析文档
ChengDu University Mental Health Website 需求分析文档 V4.0 编制人:刘雷,黄凯 日期:2019/4/28 版本修订历史记录: 版本 日期 修改内容 作者 ...
- win10台式机rtl8188eu(FW 150 UM V2.0)无线网卡无法连接wifi(无法连接到这个网络)
同一个网卡,同一个WiFi,在笔记本上能用,能连接wifi,但是在台式机上就不能连接wifi,提示“无法连接到这个网络”,如下图. win10版本都是1903.尝试换各种驱动都没解决. 最后更新主板b ...
- WTL 9.0的变化 - atlapp.h
忽然发现WTL更新到9.0.4140了,便对比了一下 8.1.12085. 先看看atlapp.h中有什么大的变动. 第61行: #if defined(_SYSINFOAPI_H_) &&a ...
- linux 以导入文件形式添加定时任务(crontab)时需要注意的坑
在实际操作过程中发现,使用导入文件形式添加定时任务时,会将用户已有的定时任务全部覆盖清理(先清空,再重新导入),所以在使用文件导入定时任务时,需要先将已有定时任务导出,然后将新任务进行追加到已有定时任 ...