[数据结构]第一章-思维题
来源:互联网 发布:襄阳seo 编辑:程序博客网 时间:2024/06/03 13:54
作业题:
1.3 相亲大会
(终于理解了最大连续子串和问题O(n)做法,开心。最朴素的做法是O(n^3),发现在第三重循环(从i到j累加)其实每次都做了重复的工作,可改进为在前一次的sum再加aj变为O(n^2)。若划分为子问题,将这一串拆成左右两个部分,中间横跨左右子串的部分(左子串的末尾一定包含,右子串的起始一定包含)相当于确定了子串末尾求往左延伸能多远,和确定了子串起始往右延伸能多远然后合并在一起,这需要O(n)时间。那么T(n) = 2*T(n/2)+O(n)。最终是个O(nlogn)的复杂度。这时我们发现,如果确定了子串的起始点或末尾点,那么就能用O(n)的时间做完。所以有了动规的做法,b[i]为以i为结束点的最大子串和,b[i] = max(b[i-1]+a[i],a[i])。发现若b[i-1]是一个负数那么显然b[i] = a[i],否则b[i] = b[i-1]+a[i]。那么就可以不用b[i]这个数组,用Max来更新遍历过程中的最大值,从第一个点开始往后加,每次更新Max,加到sum为负的时候说明现在sum包含的这一串再往后加的话已无任何贡献,舍弃掉这个点以及之前的一串,sum = 0,再从下一个点开始继续往后加。为什么这整个串都得扔掉呢,会不会有末尾的一小串的和>0呢?可以证明,如果末尾的一串>0,总和<0,那么前面的那一串和一定<0,就说明早在前面那一小串被遍历完的时候就已经扔掉了,是矛盾的。(或者理解成加到了i这个点才造成整个串<0,说明i是造成结果变小的差劲的数字,不得不舍弃掉,又因为连续子串不间断,所以前面的一串都得扔。)这就是最后的O(n)的算法。)
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int arr[100010]; int main() { int n; cin >> n; int i; for(i = 0; i < n; i++) cin >> arr[i]; int sum = 0; int Max = -1000000001; //注意连续子串和可能为负,Max不可为0 for(i = 0; i < n; i++) { sum +=arr[i]; if(sum > Max) Max = sum; if(sum < 0) sum = 0; } cout << Max << endl; return 0; }
同类问题:求连续子序列的和的绝对值最小值;连续子序列的长度的最小值….(待解决)
1.4 心存疑惑的兰
(将这串数字sort之后从小的开始往后比较,若相邻差值大于1则较小的数字加1为答案,若不存在差值大于1,那么最大的数字加1为答案。)
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int arr[1010]; int main() { int n; cin >> n; int i; for(i = 1; i <= n; i++) cin >> arr[i]; sort(arr+1,arr+1+n); bool flag = true; for(i = 1; i <= n; i++) { if(arr[i-1]+1 < arr[i]) //arr[0]=0 注意没有1的情况 { flag = false; cout << arr[i-1]+1 << endl; break; } } if(flag) cout << arr[n]+1 << endl; return 0; }
思路2:
因为n特别小只到1000,而ai的范围又特别大,那么说明这一串数字是非常离散的,只要有一个ai比1000大,那么前面就一定存在空位。所以开一个1000的bool数组flag来存数字1~1000已存在的状态,最后遍历一遍没被标记过的即为最小。
bool flag[1002]; int n; scanf("%d",&n); int i,num; for(int i = 0; i < n; i++) { scanf("%d",&num); if(num < 1001 && !flag[num]) flag[num] = true; } i = 1; while(flag[i]) i++; printf("%d\n",i);
————
练习题:
1.1 单身狗进化
(先求出阶乘再求位数显然是不可取的..因为n的最大值是25000.. 考虑到一个数n的位数等于log10(n)的整数部分+1,log(n!) = log(n)+log(n-1)+…+log(1),于是可以先求出log(n!),再加一即为答案。)
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int main() { int n; cin >> n; double sum = 0; for(int i = 1; i <= n; i++) sum+=log10((double)i); cout << (int)sum+1 << endl; return 0; }
1.2 青子的生日
(好像是挑战里的原题诶0 0 要尽可能玩的多,那么希望每个游戏都能结束得越早越好,这样就有更大机会玩更多。所以按照结束的越早越好来排序这些区间,然后从第一个开始计数,然后找到比结束时间大的下一个游戏的开始时间,cnt++,直到遍历完)
#include<iostream> #include<cstdio> #include<cmath> #include<set> #include<algorithm> using namespace std; int i; struct play { int s; int e; }p[110]; bool cmp( const play & p1,const play & p2) { return p1.e < p2.e; } int main() { int n; cin >> n; for(i = 0; i < n; i++) cin >> p[i].s >> p[i].e; sort(p,p+n,cmp); int cnt = 1; int now = p[0].e; for(i = 1; i < n; i++) { if(now <= p[i].s) { cnt++; now = p[i].e; } } cout << cnt << endl; return 0; }
- [数据结构]第一章-思维题
- 数据结构思维 第一章 接口
- 数据结构第一章思维导图
- 数据结构 第一章 思维导图
- 数据结构第一章思维导图
- 数据结构 第一章 《思维导图》
- 数据结构第一章思维导图
- 数据结构第一章:思维导图
- 《数据结构》第一章思维导图
- 第一章数据结构思维导图
- 数据结构第一章思维导图
- 《数据结构》第一章思维导图
- 数据结构第一章思维导图
- 数据结构第一章思维导图
- 数据结构第一章思维导图
- 数据结构第一章思维导图
- 数据结构 第一章 思维导图
- 数据结构 第一章 绪论 思维导图
- 二进制小数
- Java面试题大全(Java基础八)
- 关于group by 两个或以上条件的分析
- 四元数转化为欧拉角
- eclipse停止logcat自动滚动
- [数据结构]第一章-思维题
- java多线程与线程间通信
- QT中 No such file or directory 问题解决
- 关于微信红包的一些算法可能性
- 序章
- .Net 高效开发之不可错过的实用工具
- 第十章 String()
- Unity开发学习路线在哪里【蓝鸥Unity学习路线】
- asm技术学习