我上学期数据结构与算法拿了85分,15分丢在了算法分析设计上面。(思路,代码,分析各五分)其余全部拿到的情况下,只有对基本算法思路全部非常熟悉,才能拿到满分。所以现在开始每天一道题,为后面算法设计打基础
8.21最大容量
题目描述:
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析:
已知所有的潜在容器壁的高度,使用双指针方法。(我觉得有潜在的贪心算法)开始时,两指针分别指向最左端和最右端,然后将两个指针中较小的那一个向另一侧挪动一位。(这样才有可能找到比当前maxsize更大的容积)
代码实现:
int maxArea(vector<int>& height) {
int l=0,r=height.size()-1;
int ans=0;
while(l<r) {
int area=(r-l)*min(height[l],height[r]);
ans=max(ans,area);
if(height[l]<height[r]) l++;
else r--;
}
return ans;
}
8.22
【2010统考真题】
算法思想描述:
字符串视为ab,首先将ab分别各自倒置,得a-1b-1,再将a-1b-1整体倒置,得ba
代码:
/*2010年统考真题*/
void reserve(int R[],int from,int to) {//倒置from与to之间的元素
int i,temp;
for(int i=from;i<(to-from+1)/2;i++)
swap(R[form+i],R[to-i]);
}
void converse(int R[],int n,int p){
reserve(R,0,p-1);
reserve(R,p,n-1);
reserve(R,0,n-1);
}
算法分析:(完整版解答)
三个reserve函数的复杂度分别为O(p/2) O((n-p)/2) O(n/2)
时间复杂度O(n)
空间复杂度O(1)
【2011统考真题】
算法设计思想:
由于a,b两序列长度相等,取各自中位数a[m],b[n]进行比较,如果两个中位数相等,则该数为总序列的中位数。如果两中位数不等,则总中位数一定位于现有的两中位数之间。当a[m]>b[n]时,中位数位于a串前半段或b串后半段中,反之亦然。将中位数可能位于的两个半段子串作为新的序列再比较,直到两个中位数相等,即为所求总中位数。
代码描述:
(设计思想有点点问题,我写的是递归实现,由于涉及思想的bug即两中位数不相等,造成无穷递归)下面描述正确的算法思想与代码。
算法设计思想:
分别求A,B的中位数a,b:
若a==b 则a或b为所求中位数
a<b 则舍弃A较小的一半,同时舍弃B较大的一段,并且两次舍弃的长度相等
a>b 则舍弃B较小的一半,同时舍弃A较大的一段
重复以上步骤,直到两个序列中只含一个元素为止
代码描述:(其实我觉得非递归更好,因为没有递归栈,空间复杂度能再低一点)
int M_Search(int a[],int b[],int n) {
int s1=0,d1=n-1,s2=0,d2=n-1,m1,m2;
while(s1!=d1||s2!=d2) {
m1=(s1+d1)/2;
m2=(s2+d2)/2;
if(a[m1]==b[m2])
return a[m1]; //满足条件1
if(a[m1]<b[m2]) { //满足条件2
if((s1+d1)%2==0) { //若元素个数为奇数
s1=m1; //舍弃a中间点以前的部分且保留中间点
d2=m2; //舍弃b中间点以后部分且保留中间点
} else {
s1=m1+1;
d2=m2;
}
}
else {
if((s1+s2)%2==0) {
d1=m1;
s2=m2;
}
else {
s1=m1;
s2=m2+1;
}
}
}
return a[s1]<b[s2]?a[s1]:b[s2];
}
8.23
今天看了评分标准,写n2算法可以拿10分,花费大量时间思考最优解是得不偿失的,不应该在这里花费大量时间,于是我打算继续以王道考研书为参考,加快复习步伐,先将所有知识过一遍。先求全面与整体。
【2013统考真题】
标准答案:
算法描述:
从后向前扫描数组元素,标记出一个可能成为主元素的元素num,然后重新计数,确认num是否为主元素。
算法可以分为以下两步:
1.选取候选主元素,依次扫描所给的每个整数,将第一个遇到的整数num保存到c中,记录num的出现次数为1,若遇到下一个整数仍等于num则计数加一,否则计数减一,当计数减到0时,将遇到的下一个整数保存到c中,计数重新记为1,开始新一轮计数,重复以上步骤,直到扫描完全部数组元素。
2.判断c中元素是否是真正的主元素。
再次扫描该数组,统计c中元素出现的次数,若大于等于n/2,则为主元素,否则序列中不存在主元素。
算法实现:(我觉得书上写得有点丑)
int majority(int a[],int n) {
int i,c,count=1;
c=a[0];
for(int i=1;i<n;i++)
if(a[i]==c) count++;
else
if(count>0) count--;
else {
c=a[i];count=1;
}
if(count>0)
for(i=count=0;i<n;i++)
if(a[i]==c) count++;
if(count>n/2) return c;
else return -1;
}
显然,时间复杂度O(n),空间复杂度T(1)
当然,如果不这么做自然也可以。
算法描述:将数组进行排序,依次计算每个数字出现的次数,当该次数大于n/2即为所求的主元素
算法设计:
/*当然要用快排啦*/
void qsort(int a[],int l,int r) { //有点忘记了
if(l>r) return;
int tmp=a[l];
int i=l;
int j=r;
while(i!=j) {
while(a[j]>=tmp&&j>i) j--;
while(a[i]<=tmp&&j>i) i++;
if(j>i) swap(a[i],a[j]);
}
a[l]=a[i];
a[i]=tmp;
qsort(a,l,i-1);
qsort(a,i+1,r);
}
int majority(int a[],int n) {
qsort(a,0,n-1);//排序
int c=1;
int i=0;
while(i<n) {
while(a[i]==a[i+1]) {
c++; i++;
}
if(c>n/2) return a[i-1];
i++;
c=1;
}
return -1;
}
该算法的时间复杂度O(nlogn)空间复杂度O(1)