3.7排序&查找练习&时间空间复杂度
3.7排序&查找练习&时间空间复杂度
目录
洛谷题目传送门
- P1478 陶陶摘苹果(升级版)
- P1918 保龄球
- P1678 烦恼的高考志愿
- P2249 【深基13.例1】查找
- P1923 【深基9.例4】求第 k 小的数
- P1102 A-B 数对
- P7910 [CSP-J 2021] 插入排序
P1478 陶陶摘苹果(升级版)
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
struct T{ double x,y; }t[N];
bool cmp(T a, T b){ return a.y<b.y; }//自定义结构体排序
int main(){
double n,s,a,b,ans=0; cin>>n>>s>>a>>b;//题目未给出数据类型,double保险
for(int i=1; i<=n; i++) cin>>t[i].x>>t[i].y;
sort(t+1, t+1+(int)n, cmp);//这里的n参数应当为整型,于是强制转换
for(int i=1; i<=n; i++){
if(t[i].x <= a+b && t[i].y<=s){ s-=t[i].y; ans++; }
}
cout<<ans<<endl; return 0;
}
P1918 保龄球
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
struct T{ int id, value; }t[N];
bool cmp(T a, T b){ return a.value<b.value; }
int binSearch(T arr[], int n, int m){
int l=1, r=n, mid;
while(l<=r){
mid=(l+r)/2;
if(arr[mid].value<m) l=mid+1;
else if(arr[mid].value>m) r=mid-1;
else if(arr[mid].value==m) return arr[mid].id;
}
return 0;
}
int main(){
int n,v; scanf("%d", &n);
for(int i=1; i<=n; i++){ scanf("%d", &v); t[i].id=i, t[i].value=v; }
sort(t+1, t+n+1, cmp); int q,m; scanf("%d", &q);
while(q--){
scanf("%d", &m); printf("%d\n", binSearch(t, n, m));
} return 0;
}
P1678 烦恼的高考志愿
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int a[N], b[N];
int binSearch(int arr[], int n, int m){
int l=1,r=n, mid;
while(l<r){//二分查找第一个不小于m的元素下标 r,注意没有等于了
mid=(l+r)/2;
if(arr[mid]<m) l=mid+1;
else if(arr[mid]>=m) r=mid;
}
if(r>1 && abs(arr[r-1]-m) < abs(arr[r]-m)) r=r-1; //找差距最小的元素下标
return r;
}
int main(){
int m,n; cin>>m>>n;
for(int i=1; i<=m; i++) cin>>a[i];
for(int i=1; i<=n; i++) cin>>b[i];
sort(a+1, a+1+m); long long ans=0;
for(int i=1; i<=n; i++){
int id = binSearch(a, m, b[i]); ans += abs(a[id]-b[i]);
}
printf("%lld\n", ans); return 0;
}
P2249 【深基13.例1】查找
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,a[N], b[N];
int binSearch(int* arr, int x){
int l=1, r=n,mid;
while(l<=r){
mid=(l+r)/2;
if(arr[mid]<x) l=mid+1;
else if(arr[mid]>x) r=mid-1;
else if(arr[mid]==x){
if(mid>1 && arr[mid-1]==x) r=mid-1;
else return mid;
}
}
return -1;
}
int main(){
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=m; i++) cin>>b[i];
for(int i=1; i<=m; i++) printf("%d ", binSearch(a, b[i]));
return 0;
}
P1923 【深基9.例4】求第 k 小的数
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
int a[N], n, k;
void quickSort(int*arr, int l, int r){
if(l>=r) return;
int i=l, j=r, mid=arr[l];
while(i<j){
while(i<j && arr[j]>mid) j--; a[i]=a[j];
while(i<j && arr[i]<=mid) i++; a[j]=a[i];
}
a[i]=mid;
if(k<=i-1) quickSort(arr, l, i-1); //只对答案区间进行排序
if(k>=i+1) quickSort(arr, i+1, r);
}
int main(){
scanf("%d%d", &n, &k);
for(int i=0; i<n; i++) scanf("%d", &a[i]);
quickSort(a, 0, n-1); // nth_element(a, a+k, a+n);
printf("%d\n", a[k]);
return 0;
}
P7910 [CSP-J 2021] 插入排序
#include<bits/stdc++.h>//50分,超时
using namespace std;
const int N=1e4;
struct T{ int id, value; }a[N], b[N];
bool cmp(T a, T b){ return a.value<b.value; }
int find(T arr[], int n, T x){
for(int i=1; i<=n; i++){
if(arr[i].value==x.value && arr[i].id==x.id) return i;
}
return -1;
}
void insertSort(T arr[], int n){
for(int i=1; i<=n; i++){
for(int j=i; j>=2; j--){
if(arr[j].value < arr[j-1].value){
T t = arr[j-1]; arr[j-1] = arr[j]; arr[j] = t;
}
}
}
}
int main(){
int n,q; scanf("%d%d", &n, &q);
for(int i=1; i<=n; i++){ scanf("%d", &a[i].value); a[i].id=i; }
for(int i=1; i<=q; i++){
int f,x,v; scanf("%d%d", &f, &x);
if(f==1){
scanf("%d", &v); a[x].value=v;
}else if(f==2){
for(int i=1; i<=n; i++) b[i]=a[i];
insertSort(b, n);
cout<<find(b, n, a[x])<<endl;
}
}
return 0;
}
满分解法参考 CSP2021 J2/S2参考解析
时间复杂度&空间复杂度
在进行算法分析时,语句总的执行次数 \(T(n)\) 是关于问题规模n的函数,进而分析 \(T(n)\) 随 \(n\) 的变化情况并确定 \(T(n)\) 的数量级。
算法的时间复杂度,也就是算法的时间量度,记作:\(T(n}=O(f(n))\), 这样的表示方法被称为大\(O\)表示法。
它表示随问题规模 \(n\) 的增大,算法执行时间的增长率和 \(f(n)\) 的增长率相同,称作算法的渐近时间复杂度,简称为时间复杂度。
其中 \(f(n)\) 是问题规模n的某个函数。
\[f(n)=k,k为常数时,时间复杂度为O(1),可以称为常数阶。\\
f(n)=n时, 时间复杂度为O(n), 可以称为线性阶。\\
f(n)=logn时, 时间复杂度为O(logn), 可以称为对数阶。\\
f(n)=nlogn时,时间复杂度为O(nlogn),可以称为nlogn阶。\\
f(n)=n^2时, 时间复杂度为O(n^2), 可以称为平方阶。\\
f(n)=n^3时, 时间复杂度为O(n3), 可以称为立方阶。\\
f(n)=2^n时, 时间复杂度为O(2^n), 可以称为指数阶。\\
f(n)=n!时, 时间复杂度为O(n!), 可以称为阶乘阶。\\
f(n)=sqrt(n)时,时间复杂度为O(sqrt(n)),可以称为平方根阶\\
\]
算法时间复杂度:
\[O(1)<O(logn)<O(sqrt(n))<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)
\]
举例:对一个数据集中的N个元素进行排序,N<1e7。
当我们使用插入排序对数据集进行排序时,程序如下:
for(int i=1; i<=n; i++){ //执行次数:n
for(int j=i; j>1; j--){ //执行次数:n + n-1 + n-2 +...+ 1 = (1+n)*n/2
if(arr[j]<arr[j-1]){
int temp=a[j]; a[j]=a[j-1]; a[j-1]=temp;
}
}
}
上述程序总的执行次数:\(n+3*(1+n)*n/2 = O(n^2)\);这时候需要取大头 \(n^2\)。
当N=1e7时,=1e14 > 5e8,故该算法不是正解,需要考虑其他的解法。
空间复杂度同样是对所在空间进行估计,但是由于程序的确定,那么一般空间大小就确定了,当然动态空间除外。
可以对所用空间的主要部分进行估算,不超过限制空间大小即可。sizeof(a)/1024.0/1024<<"MB";