求数组两两之差绝对值最小值的O(n)算法

中间件XL 2007-09-23 07:14:25
引理:数组每个元素加上某整数,数组两两之差绝对值不变。
0: 设数组为a[n],遍厉a找到最小最大值min/max
for i=1 to n
a[i]=a[i]+(-min)+1; // 即令最小元素为1。
max=max+(-min)+1;
min=1;
令minABS=max-min+1
len=max-min;
1:
for i=1 to max
begin
遍厉数组,数组每个元素-1,并计算-1后数组元素0增加的个数zeroAdd.
len=len+1;
if zeroAdd>2 then minABS=0; 结束。
if zeroAdd=1 then
begin
if (len<minABS) then
minABS=len;
len=0;
end
end


...全文
1708 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
超级大笨狼 2007-10-16
  • 打赏
  • 举报
回复
研究了好几天,写出来一个看起来象O(n)的算法,O(nlog)就不用写了.

using System;


namespace MinABS
{
class Program
{
static void Main(string[] args)
{
int n = 100;
int[] a = new int[n];
Random rand = new Random();
int min = int.MaxValue;
int max = int.MinValue;
Console.WriteLine("产生了" + n + "个数据的实验数组,");
for (int i = 0; i < n; i++)
{
//赋值并且取到最大最小值
//a[i] = rand.Next(int.MinValue, int.MaxValue);
a[i] = rand.Next(-100, 100);
if (a[i] < min) { min = a[i]; }
if (a[i] > max) { max = a[i]; }
Console.Write(a[i] + " ");
}
Console.WriteLine();
Console.WriteLine("在O(n)内得到最大最小分别是:");
Console.WriteLine(max + "和" + min);

long offset = (long)max + Math.Abs((long)min);
//规划数组的长度。每个byte有8位长
int len = (int)(offset >> 3) +1 ;
Byte[] B = new Byte[len];
int kkkk = 0;
bool IsSame = false;//是否有重合点标记

//O(n)的时间内分配到了Byte[]中。

for (int i = 0; i < n; i++)
{
offset = (long)a[i] - (long)min;
int index = (int)(offset >> 3);
int temp = B[index];
//把末k位变成1
//把右数第k位变成1 例如:(00101001->00101101,k=3) x | (1 << (k-1))

int tempOffSet = (1 << ( (int)(offset & 7) ) );
//判断重合
if (!IsSame)
{
kkkk = temp & tempOffSet;
if ((temp & tempOffSet) >= 1)
{
IsSame = true;
//如果0算最小距离就在这里退出吧。本代码判断重合,但没把0作为结果。
}
}
int bbb = B[index];
B[index] |= (Byte)(tempOffSet);
int aaa = B[index];

}
//最小距离初始为最大。

Console.WriteLine("在O(n)的时间内分配到了Byte[]中,正在计算最小距离,请稍候。。。。。");

long minABS = long.MaxValue;
long lastIndex = -1;

//在常数范围内循环,复杂度不增加。最坏的情况是32*int.MaxValue次。

for (int i = 0; i < B.Length; i++)
{
//if (B[i] == 0) { continue; }
//在常数范围内循环,复杂度不增加。
for (int k = 0; k < 8; k++)
{
if (((B[i] >> k) & 1) == 1)
{
if (lastIndex >= 0)
{
long temp = ((long)i << 3) + k - lastIndex;
if (temp < minABS)
{
minABS = temp;
Console.WriteLine("目前得到了最小距离:" + minABS);
}
}
lastIndex = (i << 3) + k;
}
}
}
if (IsSame)
{ Console.WriteLine("有重合点"); }
else
{ Console.WriteLine("无重合点"); }

Console.WriteLine("不考虑重合最小距离是:" + minABS);
Console.WriteLine("总复杂度是:O(n)");

Console.ReadLine();

}


}
}

中间件XL 2007-09-28
  • 打赏
  • 举报
回复
ls有道理,但max是常数,a是给定的数组。
我想问题出在题目上,复杂度是n趋于无穷时的值,此时max-min<n,必有重复的数。
此题应改为“删除数组中重复的数“比较适合,两题本质是一样。
kaishui_gu 2007-09-28
  • 打赏
  • 举报
回复
max不是常数;
可以证明max>=n:假如max<n,则在数组A[n]中肯定出现重复的数,也就是说“差绝对值最小值”为0;
LS是有道理的,LZ的算法的确比N*N慢,不过LZ算法的复杂度还真的不会算
Zricepig 2007-09-28
  • 打赏
  • 举报
回复
我靠,如果这个数组不太致密,o(Max*N)还要远慢于o(N*N)
gzc9047 2007-09-24
  • 打赏
  • 举报
回复
偶然想到一篇论文上讲的一个O(nlglgn)算法可以应用到这个问题上来,参考论文"P.van Emde Boas. Preserving order in a forest in less than logarithmic time. In Proceedings of the 16th Annual Symposium on Foundations of Computer Science, page 75-84. IEEE Computer Society, 1975"。
weicai_chen 2007-09-24
  • 打赏
  • 举报
回复
引理:数组每个元素加上某整数,数组两两之差绝对值不变。
0: 设数组为a[n],遍厉a找到最小最大值min/max
for i=1 to n
a[i]=a[i]+(-min)+1; // 即令最小元素为1。
max=max+(-min)+1;
min=1;
令minABS=max-min+1
len=max-min;
1:
for i=1 to max
begin
遍厉数组,数组每个元素-1,并计算-1后数组元素0增加的个数zeroAdd.
len=len+1;
if zeroAdd >2 then minABS=0; 结束。
if zeroAdd=1 then
begin
if (len <minABS) then
minABS=len;
len=0;
end
end



szlhj能不能将清楚点,有条理点啊,

TAOBO2 2007-09-23
  • 打赏
  • 举报
回复
可以用hash表来控制大小,但是如此的话,又会引起其它的问题
中间件XL 2007-09-23
  • 打赏
  • 举报
回复
ls的兄弟... 无言
sli_romen 2007-09-23
  • 打赏
  • 举报
回复
如果循环次数与max无关那就是对的。
照你这么说,我可以在O(n)时间内用下面的方法计算数组a[n]每个元素的阶乘和:
int foo(int n)
{
if(n == 1)
return 1;
else
return n*foo(n-1);
}
int sum = 0;
for(int i = 0;i < n;i ++)
{
sum += foo(a[i]);
}
如果a[]只有一个元素,那我就是在O(1)内计算了一个数的阶乘。不管这个数多大,我都能在常数时间内得到,我太强了,我要去拿图灵奖了
中间件XL 2007-09-23
  • 打赏
  • 举报
回复
<<数据结构C++版>>34页:
O(c*f(n))=O(f(n))
max就算多大也只是常数
sli_romen 2007-09-23
  • 打赏
  • 举报
回复
算法正不正确先不说了,单就这个循环for i=1 to max ,已经是O( max * n )的了
sli_romen 2007-09-23
  • 打赏
  • 举报
回复
a =[1,3,6,1000]
0: 设数组为a[n],遍厉a找到最小最大值min/max //min = 1,max = 1000,n = 4
for i=1 to n
a[i]=a[i]+(-min)+1; // 即令最小元素为1。 //因为min=1,元素没有改变
max=max+(-min)+1;
min=1; //同理,没有改变
令minABS=max-min+1 //minABS = 1000
len=max-min; //len = 999
1:
for i=1 to max
begin
遍厉数组,数组每个元素-1,并计算-1后数组元素0增加的个数zeroAdd. //-1后{0,2,5,999},zeroAdd = 1
len=len+1; //len = 1000
if zeroAdd >2 then minABS=0; 结束。
if zeroAdd=1 then //此时len = minABS = 1000
begin //不知楼主的程序想返回什么?
if (len <minABS) then
minABS=len;
len=0;
end
end

33,027

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧