算法设计与分析 - 李春葆 - 第二版 - pdf->word v3
1.1 第1章─概论 1.1. 练习题
. 下列关于算法的说法中正确的有( )。
Ⅰ.求解某一类问题的算法是唯一的
Ⅱ.算法必须在有限步操作之后停止
Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊
Ⅳ.算法执行后一定产生确定的结果
A. 1个 B.2个 C.3个 D.4个
. T(n)表示当输入规模为n时的算法效率,以下算法效率最优的是( )。
A.T(n)= T(n-)+,T()= B.T(n)= 2n2
C.T(n)= T(n/)+,T()= D.T(n)=3nlog2n
. 什么是算法?算法有哪些特征?
. 判断一个大于2的正整数n是否为素数的方法有多种,给出两种算法,说明其中
一种算法更好的理由。
. 证明以下关系成立:
()10n2-2n=(n2)
()2n+=(2n)
. 证明O(f(n))+O(g(n))=O(max{f(n),g(n)}) 。
. 有一个含n(n>)个整数的数组a,判断其中是否存在出现次数超过所有元素一
半的元素。
. 一个字符串采用string对象存储,设计一个算法判断该字符串是否为回文。
. 有一个整数序列,设计一个算法判断其中是否存在两个元素和恰好等于给定的整
数k。
. 有两个整数序列,每个整数序列中所有元素均不相同。设计一个算法求它们的公 共元素,要求不使用STL的集合算法。
. 正整数n(n>)可以写成质数的乘积形式,称为整数的质因数分解。例如, =**,=**,=。设计一个算法求n这样分解后各个质因数出现的次数,采 用vector向量存放结果。
. 有一个整数序列,所有元素均不相同,设计一个算法求相差最小的元素对的个 数。如序列4、、、3的相差最小的元素对的个数是3,其元素对是(,),(,), (,)。
. 有一个map<string,int>容器,其中已经存放了较多元素。设计一个算法求出其 中重复的value并且返回重复value的个数。
. 重新做第10题,采用map容器存放最终结果。
. 假设有一个含n(n>)个元素的stack<int>栈容器st,设计一个算法出栈从栈顶
到栈底的第k(≤k≤n)个元素,其他栈元素不变。 算法设计 1.1. 练习题参考答案
. 答:由于算法具有有穷性、确定性和输出性,因而Ⅱ、Ⅲ、Ⅳ正确,而解决某一
类问题的算法不一定是唯一的。答案为C。
. 答:选项A的时间复杂度为O(n)。选项B的时间复杂度为O(n2)。选项C的时间
复杂度为O(log2n)。选项D的时间复杂度为O(nlog2n)。答案为C。
. 答:算法是求解问题的一系列计算步骤。算法具有有限性、确定性、可行性、输
入性和输出性5个重要特征。
. 答:两种算法如下:
#include <stdio.h>
#include <math.h>
bool isPrime1(int n) //方法1
{ for (int i=;i<n;i++)
if (n%i==)
return false;
return true;
}
bool isPrime2(int n) //方法2
{ for (int i=;i<=(int)sqrt(n);i++)
if (n%i==)
return false;
return true;
}
void main()
{ int n=;
printf("%d,%d\n",isPrime1(n),isPrime2(n));
}
方法1的时间复杂度为O(n),方法2的时间复杂度为n,所以方法2更好。
. 答:()当n足够大时,(10n2-2n)/( n2)=,所以10n2-2n=(n2)。
()2n+=*2n=(2n)。
. 证明:对于任意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)})。
. 解:先将a中元素递增排序,再求出现次数最多的次数maxnum,最后判断是否满
足条件。对应的程序如下:
#include <stdio.h>
#include <algorithm>
using namespace std;
第1章 概论 bool solve(int a[],int n,int &x)
{ sort(a,a+n); //递增排序
int maxnum=; //出现次数最多的次数
int num=;
int e=a[];
for (int i=;i<n;i++)
{ if (a[i]==e)
{ num++;
if (num>maxnum)
{ maxnum=num;
x=e;
}
}
else
{ e=a[i];
num=;
}
}
if (maxnum>n/)
return true;
else
return false;
}
void main()
{ int a[]={,,,,,,};
int n=sizeof(a)/sizeof(a[]);
int x;
if (solve(a,n,x))
printf("出现次数超过所有元素一半的元素为%d\n",x); else
printf("不存在出现次数超过所有元素一半的元素\n"); }
上述程序的执行结果如图1.1所示。 图1. 程序执行结果
. 解:采用前后字符判断方法,对应的程序如下:
#include <iostream>
#include <string>
using namespace std;
bool solve(string str) //判断字符串str是否为回文 { int i=0,j=str.length()-1;
while (i<j)
{ if (str[i]!=str[j])
return false; 算法设计 i++; j--;
}
return true;
}
void main()
{ cout << "求解结果" << endl;
string str="abcd";
cout << " " << str << (solve(str)?"是回文":"不是回文") << endl;
string str1="abba";
cout << " " << str1 << (solve(str1)?"是回文":"不是回文") << endl; }
上述程序的执行结果如图1.2所示。 图1. 程序执行结果
. 解:先将a中元素递增排序,然后从两端开始进行判断。对应的程序如下:
#include <stdio.h>
#include <algorithm>
using namespace std;
bool solve(int a[],int n,int k)
{ sort(a,a+n); //递增排序
int i=, j=n-;
while (i<j) //区间中存在两个或者以上元素
{ if (a[i]+a[j]==k)
return true;
else if (a[i]+a[j]<k)
i++;
else
j--;
}
return false;
}
void main()
{ int a[]={,,,,};
int n=sizeof(a)/sizeof(a[]);
printf("求解结果\n");
int k=,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=;
if (solve(a,n,k1,i,j))
printf(" 存在: %d+%d=%d\n",a[i],a[j],k1);
第1章 概论 else
printf(" 不存在两个元素和为%d\n",k1); }
上述程序的执行结果如图1.3所示。 图1. 程序执行结果
. 解:采用集合set<int>存储整数序列,集合中元素默认是递增排序的,再采用二
路归并算法求它们的交集。对应的程序如下:
#include <stdio.h>
#include <set>
using namespace std;
void solve(set<int> s1,set<int> s2,set<int> &s3) //求交集s3
{ set<int>::iterator it1,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;
}
}
void dispset(set<int> s) //输出集合的元素
{ set<int>::iterator it;
for (it=s.begin();it!=s.end();++it)
printf("%d ",*it);
printf("\n");
}
void main()
{ int a[]={,,,};
int n=sizeof(a)/sizeof(a[]);
set<int> s1(a,a+n);
int b[]={,,,,};
int m=sizeof(b)/sizeof(b[]);
set<int> s2(b,b+m);
set<int> s3;
solve(s1,s2,s3);
printf("求解结果\n");
printf(" s1: "); dispset(s1); printf(" s2: "); dispset(s2); printf(" s3: "); dispset(s3); }
上述程序的执行结果如图1.4所示。 算法设计 图1. 程序执行结果
. 解:对于正整数n,从i=2开始查找其质因数,ic记录质因数i出现的次数,当找
到这样质因数后,将(i,ic)作为一个元素插入到vector容器v中。最后输出v。对应的 算法如下:
#include <stdio.h>
#include <vector>
using namespace std;
struct NodeType //vector向量元素类型
{ int p; //质因数
int pc; //质因数出现次数
};
void solve(int n,vector<NodeType> &v) //求n的质因数分解
{ int i=;
int ic=;
NodeType e;
do
{ if (n%i==)
{ ic++;
n=n/i;
}
else
{ if (ic>)
{ e.p=i;
e.pc=ic;
v.push_back(e);
}
ic=;
i++;
}
} while (n> || ic!=);
}
void disp(vector<NodeType> &v) //输出v
{ vector<NodeType>::iterator it;
for (it=v.begin();it!=v.end();++it)
printf(" 质因数%d出现%d次\n",it->p,it->pc);
} void main()
{ vector<NodeType> v;
int n=;
printf("n=%d\n",n);
solve(n,v);
disp(v);
}
上述程序的执行结果如图1.5所示。 第1章 概论 图1. 程序执行结果
. 解:先递增排序,再求相邻元素差,比较求最小元素差,累计最小元素差的个
数。对应的程序如下:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int solve(vector<int> &myv) //求myv中相差最小的元素对的个数
{ sort(myv.begin(),myv.end()); //递增排序
int ans=;
int mindif=myv[]-myv[];
for (int i=;i<myv.size();i++)
{ if (myv[i]-myv[i-]<mindif)
{ ans=;
mindif=myv[i]-myv[i-];
}
else if (myv[i]-myv[i-]==mindif)
ans++;
}
return ans;
}
void main()
{ int a[]={,,,};
int n=sizeof(a)/sizeof(a[]);
vector<int> myv(a,a+n);
cout << "相差最小的元素对的个数: " << solve(myv) << endl;
}
上述程序的执行结果如图1.6所示。 算法设计 图1. 程序执行结果
. 解:对于map<string,int>容器mymap,设计另外一个map<int,int>容器tmap,
将前者的value作为后者的关键字。遍历mymap,累计tmap中相同关键字的次数。一个 参考程序及其输出结果如下:
#include <iostream>
#include <map>
#include <string>
using namespace std;
void main()
{ map<string,int> mymap;
mymap.insert(pair<string,int>("Mary",));
mymap.insert(pair<string,int>("Smith",));
mymap.insert(pair<string,int>("John",));
mymap.insert(pair<string,int>("Lippman",));
mymap.insert(pair<string,int>("Detial",));
map<string,int>::iterator it;
map<int,int> tmap;
for (it=mymap.begin();it!=mymap.end();it++)
tmap[(*it).second]++;
map<int,int>::iterator it1;
cout << "求解结果" << endl;
for (it1=tmap.begin();it1!=tmap.end();it1++)
cout << " " << (*it1).first << ": " << (*it1).second << "次\n";
}
上述程序的执行结果如图1.7所示。 图1. 程序执行结果
. 解:采用map<int,int>容器mymap存放求解结果,第一个分量存放质因数,第
二个分量存放质因数出现次数。对应的程序如下:
#include <stdio.h>
#include <map>
using namespace std;
void solve(int n,map<int,int> &mymap) //求n的质因数分解
{ int i=;
int ic=;
do
{ if (n%i==)
{ ic++;
n=n/i;
}
第1章 概论 else
{ if (ic>)
mymap[i]=ic;
ic=;
i++;
}
} while (n> || ic!=);
}
void disp(map<int,int> &mymap) //输出mymap
{ map<int,int>::iterator it;
for (it=mymap.begin();it!=mymap.end();++it)
printf(" 质因数%d出现%d次\n",it->first,it->second); }
void main()
{ map<int,int> mymap;
int n=;
printf("n=%d\n",n);
solve(n,mymap);
disp(mymap);
}
上述程序的执行结果如图1.8所示。 图1. 程序执行结果
. 解:栈容器不能顺序遍历,为此创建一个临时tmpst栈,将st的k个元素出栈并
进栈到tmpst中,再出栈tmpst一次得到第k个元素,最后将栈tmpst的所有元素出栈并进 栈到st中。对应的程序如下:
#include <stdio.h>
#include <stack>
using namespace std;
int solve(stack<int> &st,int k) //出栈第k个元素
{ stack<int> tmpst;
int e;
for (int i=;i<k;i++) //出栈st的k个元素并进tmpst栈
{ e=st.top();
st.pop();
tmpst.push(e);
}
e=tmpst.top(); //求第k个元素
tmpst.pop();
while (!tmpst.empty()) //将tmpst的所有元素出栈并进栈st
{ st.push(tmpst.top());
tmpst.pop();
算法设计 }
return e;
}
void disp(stack<int> &st) //出栈st的所有元素 { while (!st.empty())
{ printf("%d ",st.top());
st.pop();
}
printf("\n");
}
void main()
{ stack<int> st;
printf("进栈元素1,2,3,4\n");
st.push();
st.push();
st.push();
st.push();
int k=;
int e=solve(st,k);
printf("出栈第%d个元素是: %d\n",k,e);
printf("st中元素出栈顺序: ");
disp(st);
}
上述程序的执行结果如图1.9所示。 图1. 程序执行结果
1.2 第2章─递归算法设计技术 1.2. 练习题
. 什么是直接递归和间接递归?消除递归一般要用到什么数据结构?
. 分析以下程序的执行结果:
#include <stdio.h>
void f(int n,int &m)
{ if (n<) return;
else
{ printf("调用f(%d,%d)前,n=%d,m=%d\n",n-,m-,n,m);
n--; m--;
f(n-,m);
printf("调用f(%d,%d)后:n=%d,m=%d\n",n-,m-,n,m);
}
第1章 概论 }
void main()
{ int n=,m=;
f(n,m);
}
. 采用直接推导方法求解以下递归方程:
T()=
T(n)=T(n-)+n 当n>
. 采用特征方程方法求解以下递归方程:
H()=
H()=
H()=
H(n)=H(n-)+9H(n-)-9H(n-) 当n>
. 采用递归树方法求解以下递归方程:
T()=
T(n)=4T(n/)+n 当n>
. 采用主方法求解以下题的递归方程。
T(n)= 当n=
T(n)=4T(n/)+n2 当n>
. 分析求斐波那契f(n)的时间复杂度。
. 数列的首项a1=,后续奇数项和偶数项的计算公式分别为a2n=a2n-+,a2n+=a2n-
+a2n-,写出计算数列第n项的递归算法。
. 对于一个采用字符数组存放的字符串str,设计一个递归算法求其字符个数(长
度)。
. 对于一个采用字符数组存放的字符串str,设计一个递归算法判断str是否为回
文。
. 对于不带头结点的单链表L,设计一个递归算法正序输出所有结点值。
. 对于不带头结点的单链表L,设计一个递归算法逆序输出所有结点值。
. 对于不带头结点的非空单链表L,设计一个递归算法返回最大值结点的地址(假
设这样的结点唯一)。
. 对于不带头结点的单链表L,设计一个递归算法返回第一个值为x的结点的地
址,没有这样的结点时返回NULL。
. 对于不带头结点的单链表L,设计一个递归算法删除第一个值为x的结点。
. 假设二叉树采用二叉链存储结构存放,结点值为int类型,设计一个递归算法求 二叉树bt中所有叶子结点值之和。
. 假设二叉树采用二叉链存储结构存放,结点值为int类型,设计一个递归算法求 二叉树bt中所有结点值大于等于k的结点个数。
. 假设二叉树采用二叉链存储结构存放,所有结点值均不相同,设计一个递归算法 求值为x的结点的层次(根结点的层次为1),没有找到这样的结点时返回0。 算法设计 1.2. 练习题参考答案
. 答:一个f函数定义中直接调用f函数自己,称为直接递归。一个f函数定义中调
用g函数,而g函数的定义中调用f函数,称为间接递归。消除递归一般要用栈实现。
. 答:递归函数f(n,m)中,n是非引用参数,m是引用参数,所以递归函数的状态为
(n)。程序执行结果如下:
调用f(,)前,n=,m=
调用f(,)前,n=,m=
调用f(,)后,n=,m=
调用f(,)后,n=,m=
. 解:求T(n)的过程如下:
T(n)=T(n-)+n=[T(n-)+n-)]+n=T(n-)+n+(n-)
=T(n-)+n+(n-)+(n-)
=…
=T()+n+(n-)+…+
=n+(n-)+ +…++=n(n+)/=O(n2)。
. 解:整数一个常系数的线性齐次递推式,用xn代替H(n),有:xn=xn-+9xn--9xn-,
两边同时除以xn-,得到:x3=x2+9x-,即x3-x2-9x+=。
x3-x2-9x+=x(x2-)-(x2-)=(x-)(x2-)=(x-)(x+)(x-)=。得到r1=,r2=-,r3=
则递归方程的通解为:H(n)=c1+c2(-)n+c33n
代入H()=,有c1+c2+c3=
代入H()=,有c1-3c2+3c3=
代入H()=,有c1+9c2+9c3=
求出:c1=-/,c2=-/,c3=/,H(n)=c1+c2(-)n+c33n=((‒) 。 高度h为log2n+ (n/)
…… (n/) (n/)
… 第1章 概论 n
(n/) (n/) (n/) (n/)
… n
2n 22n n
图1. 一棵递归树
. 解:采用主方法求解,这里a=,b=,f(n)=n2。
因此,算法设计与分析 - 李春葆 - 第二版 - pdf->word v3的更多相关文章
- 算法设计与分析 - 李春葆 - 第二版 - html v2
1 .1 第 1 章─概论 1.1.1 练习题 1 . 下列关于算法的说法中正确的有( ). Ⅰ Ⅱ Ⅲ Ⅳ .求解某一类问题的算法是唯一的 .算法必须在有限步操作之后停止 .算法 ...
- 算法设计与分析 - 李春葆 - 第二版 - pdf->word v1
章─概论 练习题 . 下列关于算法的说法中正确的有( ).Ⅰ.求解某一类问题的算法是唯一的 Ⅱ.算法必须在有限步操作之后停止 Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊Ⅳ.算法执行后一定产 ...
- 算法设计与分析 - 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 ...
- STM32单片机应用与全案例实践 /stm32自学笔记 第二版 pdf
STM32单片机应用与全案例实践pdf https://pan.baidu.com/s/16WrivuLcHvLTwS__Zcwl6Q 4rj3 stm32自学笔记 第二版 pdf https://p ...
- 算法设计手冊(第2版)读书笔记, Springer - The Algorithm Design Manual, 2ed Steven S.Skiena 2008
The Algorithm Design Manual, 2ed 跳转至: 导航. 搜索 Springer - The Algorithm Design Manual, 2ed Steven S.Sk ...
- 算法设计与分析(李春保)练习题答案v1
1.1第1 章─概论 1.1.1练习题 1.下列关于算法的说法中正确的有(). Ⅰ.求解某一类问题的算法是唯一的 Ⅱ.算法必须在有限步操作之后停止 Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模 ...
随机推荐
- webstorm2017中添加git
1.pc中先安装git 2.在webstorm中选择VCS -> Checkout from Version Control -> Git Git Repository URL: [gi ...
- input标签自动填充问题
<input type='text' placeholder='手机号' /> <input type='text' placeholder='地址' /> <input ...
- FastJson反序列化获取不到值
今天碰到一个问题,使用fastjson反序列化,就是将JSON解析成javaBean时,一个字段值为null.后面经查,是JavaBean中的set方法写错了,fastJson解析的是利用反射通过se ...
- QSqlDatabase
QSqlDatabase 使用静态方法addDatabase来创建一个数据库连接. 如果你的程序中只有一个数据库连接,可以使用如下语句创建连接 QSqlDatabase db = QSqlDatab ...
- 序列变换(HDU-5256)【LIS】
题目链接:https://vjudge.net/problem/HDU-5256 题意:给一个数列,每一个数都不相同且为整数,现求,最少需要修改多少次才能使该数列为严格上升的. 思路:首先,对于一个严 ...
- python并发编程之协程(实践篇)
一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 对于单线程下,我们不可避免程序中出现io操作,但如果我们 ...
- Spring Cloud 中注册中心Eureka客户端配置
注册中心配置客户端(注册一个虚拟的商品服务) 一.新建项目: 1.创建一个SpirngBoot应用,增加服务注册和发现依赖 2.模拟商品信息,存储在内存中 3.开发商品列表接口 ...
- Hadoop的理解笔记
1.2Hadoop与云计算的关系1.什么是云计算:一种基于互联网的计算,在其中共享的资源.软件和信息以一种按需的方式提供给计算机和设备 , 就如同日常生活中的电网一样. 什么是Hadoop:Hadoo ...
- go 包的概念
------------------------------------------------------------------ package main import ( "fmt&q ...
- [eclipse]UML之AmaterasUML 插件
软件体系结构分析软件设计模式要求给出相应设计模式源码对应的UML类图,在此之前我安装过一种UML插件,可以自动生成一个源码包对应的UML类图,但是重装过系统,所以软件包括eclipse都重新下载了新的 ...