目录
A 数组合并
题目描述
编写一个程序,将两个有序数组合并成一个更大的有序数组,要求时间复杂度为O(n)。
输入
多组数据输入,每组输入包括两行,每行第一个数字为数组长度n,然后输入n个有序整数。
输出
输出合并后的数组(升序),每组输出用一个空行隔开。
样例输入 Copy
3 1 3 5
3 2 4 6
2 1 2
4 3 4 5 6
样例输出 Copy
1 2 3 4 5 6
1 2 3 4 5 6
分析:将两个有序数组 合并成 一个有序数组
我们可以专门开辟一个 数组 来存放这个 合并后的 数组
用一个for循环即可实现 数组合并。
主要思想就是,两个有序数组之间的比较,谁小谁就先放入,如果某一有序数组没值了,就把另一个有序数组剩下的值放入
具体看代码实现
代码实现:c语言
#include <stdio.h>
#include <stdlib.h>
int main (){
int a[200];
int b[200];
int c[200];
int al;
int bl;
while(~scanf("%d",&al)){
for(int i=0;i<al;i++)
scanf("%d",&a[i]);
scanf("%d",&bl);
for(int i=0;i<bl;i++)
scanf("%d",&b[i]);
merge(a,b,c,al,bl);
for(int i=0;i<al+bl;i++)
printf("%d ",c[i]);
printf("\n");
printf("\n");
}
return 0;
}
void merge(int a[],int b[],int c[],int al,int bl){
int i=0;
int j=0;
int k=0;
while(i<al&&j<bl){
if(a[i]<b[j])
c[k++]=a[i++];
else
c[k++]=b[j++];
}
while(i<al&&j>=bl){
c[k++]=a[i++];
}
while(j<bl&&i>=al){
c[k++]=b[j++];
}
}
B 归并排序
题目描述
编写一个程序,使用分治策略实现二路归并排序(升序)。
输入
多组输入,每组第一个数字为数组长度,然后输入一个一维整型数组。
输出
输出排序之后(升序)的一维整型数组,每组输出占一行。
样例输入 Copy
6 1 8 6 5 3 4
5 12 42 2 5 8
样例输出 Copy
1 3 4 5 6 8
2 5 8 12 42
分析:要用到上一题的两两归并,归并排序实际上就是,先分治,再不断两两归并就得到了整个排序
代码实现:c语言
#include <stdio.h>
#include <stdlib.h>
int main (){
int c[200];
int d[200];
int cl;
while(~scanf("%d",&cl)){
for(int i=0;i<cl;i++)
scanf("%d",&c[i]);
sort(c,d,0,cl-1);
for(int i=0;i<cl;i++)
printf("%d ",d[i]);
printf("\n");
}
return 0;
}
void merge(int c[],int d[],int s,int m,int t){
int i=s;
int j=m+1;
int k=s;
while(i<=m&&j<=t){
if(c[i]<c[j])
d[k++]=c[i++];
else
d[k++]=c[j++];
}
while(i<=m&&j>t){
d[k++]=c[i++];
}
while(j<=t&&i>m){
d[k++]=c[j++];
}
}
void sort(int c[],int d[],int s,int t){
if(s<t){
int m=(s+t)/2;
sort(c,d,s,m);
sort(c,d,m+1,t);
merge(c,d,s,m,t);
copy(c,d,s,t);
}
}
void copy(int c[],int d[],int s,int t){
for(int i=s;i<=t;i++)
c[i]=d[i];
}
C 第k小元素
题目描述
输入一个整数数组,请求出该数组的第k小元素。要求时间复杂度为O(n)。
输入
每组输入包括两行,第一行为一个整数数组,两个数字之间用空格隔开;第二行为k值。数组中元素个数小于10^9。
输出
输出第k小元素的值。
样例输入 Copy
2 5 6 1 8 7 9
2
样例输出 Copy
2
分析:此题乍一看,想直接排序,再找。
但是好像也可以用分区来写。我们先引用 快排里的patition方法进行分区
if 分区一次之后,k值比前面的值个数小,那么要找的数肯定就在前面的区域
如果大,肯定就在后面的区域里。当然,如果相等,那么肯定就是这个数咯。
每次分区找数时,根据比较k的大小,要进行k的更新
if k小于前面值的个数,那么依然可以继续递归前面区域的第k小值。
else 就要递归后面区域的第 k-j 小值。
代码实现:c语言
#include <stdio.h>
#include <stdlib.h>
int main (){
int n;
int a[200];
int k;
char c;
while(~scanf("%d",&a[0])){
int n=0;
while(scanf("%d",&a[++n])){
if(c=getchar()=='\n') break;
}
scanf("%d",&k);
int z=solve(a,0,n,k);
printf("%d",z);
printf("\n");
}
return 0;
}
int patition(int a[],int p,int q){
int j,i=p;
int x=a[p];
for(j=p+1;j<=q;j++)
{
if(a[j]<x){
i++;
swap(a,i,j);
}
}
swap(a,i,p);
return i;
}
int solve(int a[],int p,int q,int k){
if(p==q) return a[p];
if(p<q)
{
int i=patition(a,p,q);
int j=i-p+1;
if(j==k) return a[i];
if(j>k) return solve(a,p,i,k);
if(j<k) return solve(a,i+1,q,k-j);
}
}
void swap(int a[],int i,int j){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
D 找中位数
题目描述
请设计一个算法,不排序,快速计算出一个无序数列的中位数。 时间复杂度要求为O(n)。
如果有奇数个元素,中位数则是数组排序后最中间的那个数字。
如果是偶数个元素,中位数则是数组排序后最中间两个元素的平均值。
输入
有多组输入,每组输入的第一行为n(1<=n<=1e5),表示该数列的元素个数。
第二行为n个整数组成的无序数列
输出
每组样例输出一行,表示该无序数列的中位数。
若为偶数,请保留三位小数
若为奇数,直接输出
样例输入 Copy
5
5 3 2 1 4
样例输出 Copy
3
分析:这题在做过找第k小元素之后就变得很简单。
首先中位数,我们可以直接得出下标,将其作为要找的第k小元素即可
当然啦,考虑复杂点的,就是要求两个中位数,再求出其两数的中位数。
为了省精力,我就直接在上面改了,嘿嘿嘿
代码实现:c语言
#include <stdio.h>
#include <stdlib.h>
int main (){
int n;
int a[200000];
while(~scanf("%d",&n)){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
if(n%2==1)
{
int k=n/2+1;
int z=solve(a,0,n-1,k);
printf("%d",z);
printf("\n");
}
else{
int k1=n/2;
int k2=n/2+1;
double z1=solve(a,0,n-1,k1);
double z2=solve(a,0,n-1,k2);
double z=(z1+z2)/2;
printf("%.3lf",z);
printf("\n");
}
}
return 0;
}
int patition(int a[],int p,int q){
int j,i=p;
int x=a[p];
for(j=p+1;j<=q;j++)
{
if(a[j]<x){
i++;
swap(a,i,j);
}
}
swap(a,i,p);
return i;
}
int solve(int a[],int p,int q,int k){
if(p==q) return a[p];
if(p<q)
{
int i=patition(a,p,q);
int j=i-p+1;
if(j==k) return a[i];
if(j>k) return solve(a,p,i,k);
if(j<k) return solve(a,i+1,q,k-j);
}
}
void swap(int a[],int i,int j){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
E 棋盘覆盖问题
题目描述
在一个n×n (n = 2k)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。
在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
输入
多组测试用例,每组测试用例包括两部分,
第一部分为方格的宽度n,
第二部分则为方格,特殊方格为-1,其他方格为0。
输出
输出覆盖后的方案
样例输入 Copy
4
-1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
样例输出 Copy
-1 2 4 4
2 2 1 4
3 1 1 5
3 3 5 5
分析:棋盘覆盖问题也是一个分区的问题,主要是把盘不断的分成四个小正方形
然后逐个分析,这里要注意那个if ..else 语句都是并列的。只要一个符合,那么其他三个都不符合,
也就是要覆盖。
假设,等等我们就看样例吧,我们首先总是以左上角为标准坐标,然后把这个盘分成四个相当的小正方形。
然后这么一个特殊方格在第一个方框区域内(先左后右,先上后下),也就是-1,于是我们把剩下三个方框区域靠近
盘最中心的地方涂了颜色。刚好构成一个L。接着,我们继续递归,在第一个正方形方框中,我们继续以左上角为标准坐标
同时以-1为特殊方格,其他三个正方形中,分别以其左上角为标准坐标,并且以最靠近中心的涂了颜色的格子为特殊方格。
......
哈哈哈哈,具体请看代码,看我直接手写。
代码分析:c语言
#include <stdio.h>
#include <stdlib.h>
int board[200][200];
int title=0;
int main (){
int n;
while(~scanf("%d",&n)){
int th;
int tl;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&board[i][j]);
if(board[i][j]==-1){
th=i;
tl=j;
}
}
boardcheck(0,0,th,tl,n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
printf("%d ",board[i][j]);
if((j+1)%n==0)
printf("\n");
}
title=0;
}
return 0;
}
void boardcheck(int bh,int bl,int th,int tl ,int size){
if(size==1) return;
int t=++title;
int s=size/2;
if(th<s+bh&&tl<s+bl)
{
boardcheck(bh,bl,th,tl,s);
}
else{
board[s+bh-1][s+bl-1]=t;
boardcheck(bh,bl,s+bh-1,s+bl-1,s);
}
if(th>=s+bh&&tl<bl+s){
boardcheck(bh+s,bl,th,tl,s);
}
else{
board[bh+s][bl+s-1]=t;
boardcheck(bh+s,bl,bh+s,bl+s-1,s);
}
if(th<s+bh&&tl>=bl+s){
boardcheck(bh,bl+s,th,tl,s);
}
else{
board[bh+s-1][bl+s]=t;
boardcheck(bh,bl+s,bh+s-1,bl+s,s);
}
if(th>=s+bh&&tl>=s+bl){
boardcheck(s+bh,s+bl,th,tl,s);
}
else{
board[s+bh][s+bl]=t;
boardcheck(s+bh,s+bl,s+bh,s+bl,s);
}
}
F 大整数除法
题目描述
使用分治算法实现两个大整数相乘。
输入
两个十进制大整数,满足每一个整数长度为2^n且两个大整数的长度相等。(多组数据)
输出
两个大整数的乘积。
样例输入 Copy
1234 5678
样例输出 Copy
7006652
分析:大整数除法原理就是把两乘数分治,分解为加法进行运算
具体请看代码:
直接手写
代码分析:c语言
#include <stdio.h>
#include <stdlib.h>
int main (){
int x;
int y;
while(~scanf("%d %d",&x,&y)){
int n=0;
int i=1;
while(i<=x){
i*=10;
n++;
}
int z=dacheng(x,y,n);
printf("%d",z);
printf("\n");
}
return 0;
}
int dacheng(int x,int y,int n){
int sign2=sign(x)*sign(y);
x=abs(x);
y=abs(y);
if(x==0||y==0) return 0;
if(n==1) return sign2*x*y;
int a=x/pow(10,n/2);
int b=x-a*pow(10,n/2);
int c=y/pow(10,n/2);
int d=y-c*pow(10,n/2);
int ac=dacheng(a,c,n/2);
int bd=dacheng(b,d,n/2);
int abcd=dacheng(a-b,d-c,n/2)+ac+bd;
return sign2*(ac*pow(10,n)+abcd*pow(10,n/2)+bd);
}
int sign(int x){
if(x<0) return -1;
return 1;
}