Chinaunix首页 | 论坛 | 博客
  • 博客访问: 923714
  • 博文数量: 74
  • 博客积分: 10001
  • 博客等级: 上将
  • 技术积分: 2609
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-04 19:54
文章存档

2015年(1)

2009年(2)

2008年(71)

我的朋友

分类: WINDOWS

2008-08-18 20:13:55

水木上一个算法题:

已知:
f(1) = {1}
f(2) = {1,2}
f(3) = {3,1,2}
f(4) = {2,3,1,4}
f(5) = {4,2,5,1,3}
f(6) = {3,6,2,4,1,5}
f(7) = {7,3,5,2,6,1,4}

求: f(8) = ?  f(n)=?,用程序实现之,时间复杂度要求O(n)。

这事上面例子的推导公式:

f(n) = ++f(n-1)[1..n-1] + 1 + f(n-1)[0]

f(n) 是 f(n-1) 列表中每一项自增一, 并将第一项移动到最后的过程.

PowerShell利用管道(非O(n)复杂度算法):

PS C:\> 9..3 | % {$i=,1; $r=1,2} { $r = @(1..$($r.count-1) | %{ $r[$_] + 1 }) + $i + ++$r[0] } {"$r"}
7 4 8 3 6 2 9 1 5

这里的技巧就是用 .. 和管道进行迭代操作, 可以避免我们使用循环结构. 请勿迭代超过1000的数值, 效率很差.

一个更加快速的算法, 现在唯一的开销就是搜索槽的开销. 性能还算不错, 我的机器上算3000的序列, 需要1s:

$len = 10; 1..$len | % {$a = New-Object System.Object[] $len; $pos = $len - 2} `

{ $a[$pos] = $_;

for ($i = 0; ($i -lt 2) -and ($_ -lt $len);) {

  if ($a[--$pos] -eq $null) { $i++; continue }

  if ($pos -lt 0) { $pos += $len }

}

} {"$a"}

 

最后的一个修改版本, 利用ArrayList类似链表的性质, 减少了搜索槽的不必要开销: 比上面的算法基本上快了1倍:

PS C:\> Measure-Command { $len = 20000; 1..$len | % {$a = New-Object System.Object[] $len;
>> $b = New-Object System.Collections.ArrayList $len;
>> 0..$($len-1) | %{ [void] $b.Add($_) };
>> $pos = $len - 2;
>> } `
>> {
>>     $a[$b[$pos]] = $_;
>>     [void] $b.RemoveAt($pos);
>>     if ($_ -lt $len) {
>>         $pos -= 2;
>>         while ($pos -lt 0) { $pos += $b.count }
>>     } `
>> } {"$a"}
>> }
>>


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 3
Milliseconds      : 314
Ticks             : 33142915
TotalDays         : 3.83598553240741E-05
TotalHours        : 0.000920636527777778
TotalMinutes      : 0.0552381916666667
TotalSeconds      : 3.3142915
TotalMilliseconds : 3314.2915

 

阅读(2879) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~