寻找绝对值最小的对儿

问题:

有一个整数数组,请求出两两之差绝对值最小的值(记住,只要得出最小值即可,不需要求出是哪两个数)。

想法:

1.最起码的想法自然就是穷举了,复杂度相当高,两个循环,O(n^2),其实也不是很高哦。

2.适当变换一下题目的说法,两两绝对值之差最小,想象一下数轴,绝对值是两者距离,距离之差最小,就是数轴上的数距离最小,那排序就是很自然地想法了,排序之后的搜索过程复杂度为O(n),也就是说,如果采用搜索法,复杂度下限就是Ω(n)。

接下来是排序算法,根据《算法导论》,基于比较的排序的渐进下限O(nlgn),目前性能最好最实用的当属快排了,应用快排之后的算法复杂度当为O(nlgn)。

不基于比较的算法可以把复杂度进一步拉下来,达到O(n),计数排序要求存储器的支持,数据可能达不到要求;基数排序要提取基数,隐含了大量的除法操作;桶排序要求分散均匀,而均匀分散可以采用散列技术,只要求用一个单调函数即可。

综上,基于搜索和排序的算法可以把复杂度降到O(n)。

实现:

1.强势穷举

#define <stdlib.h>
#define <stdio.h>
#define LEN 64
int main(){
int arr[LEN], back[LEN], i, j, md = 0xffff, diff;
for(i = 0; i < LEN; ++i){
arr[i] = rand()%0xfff;
}
for(i = 0; i < LEN; ++i){
for(j = i+1; j < LEN; ++j){
diff = arr[j] > arr[i] ? arr[j] - arr[i]:arr[i] - arr[j];
if(diff == 0){
printf("arr[%d] == arr[%d]\n", i, j);
continue;
}
if(diff < md){
md = diff;
}
}
}
printf("min = %d\n", md);
return 0;
}

2.基数排序

#include <stdio.h>
#include <stdlib.h>
#define LEN 64
void count_sort(int *arr, int len, int *buf, int bfsz){ //计数排序
int i, j;
for(i = 0; i < bfsz; ++i){
buf[i] = 0;
}
for(i = 0; i < len; ++i){
++buf[arr[i]];
}
for(i = 1; i < bfsz; ++i){
buf[i] += buf[i-1];
}
}
void base_sort(int *arr, int len, int n){ //基数排序
int buf[10];
int div = 10, base = 1, i, d; //div和base确定一个位阶,位阶是说十位数,百位数,千位数这样的位阶
int ds[len]; //基数集,取值范围0~9,所有数相同位阶的数值,比如1234的十位阶为3,百位阶为2
int back[len]; //原数组的备份
for(d = 0; d < n; ++d){
for(i = 0; i < len; ++i){ //备份
back[i] = arr[i];
}
for(i = 0; i < len; ++i){ //计算位阶
ds[i] = arr[i]%div;
ds[i] /= base;
}
count_sort(ds, len, buf, 10); //以位阶值排序
for(i = len-1; i >= 0; --i){ //调换整个数组的顺序
arr[--buf[ds[i]]] = back[i];
}
div *= 10;
base *= 10;
}
}
int main(){
int arr[LEN], i, md = 0xffff, diff;
for(i = 0; i < LEN; ++i){
arr[i] = rand()&0xffff;
}
base_sort(arr, LEN, 5);
for(i = 1; i < LEN; ++i){
diff = arr[i] - arr[i-1];
if(diff == 0){
printf("arr[%d] == arr[%d]\n", i, i-1);
continue;
}
if(diff < md){
md = diff;
}
}
printf("min = %d\n", md);
return 0;
}

基数排序看起来有点乱,而且空间局部性看起来不太好,需要备份一个数表,算法的复杂度系数嘛,每个函数里面len次循环多达4个,10次循环有2个,还具有一个lgn/lg10的外围循环,呃~~~~

转载于:https://www.cnblogs.com/huyc/archive/2011/10/11/2207552.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值