最短最长递增子序列码


11

挑战是编写最短的实现以找到最长的递增子序列

示例:令S为序列1 5 7 1 8 4 3 5 [S的长度= 8]

  • 我们有1个长度为0的子序列[会认为它正在增加]
  • 长度为1 {1,5,7,8,4,3}的6个子序列[它们都被认为正在增加]
  • (7 * 8)/ 2个长度为2的子序列[但是我们将删除重复项],递增的子序列为深黑色。
    { 15,17,11,18,14,13,57,51,58,54,53,55,71,78,74,73,75,84,83,85,43,45,35 }

[请注意,我们只对严格增加子序列感兴趣]

[您无法更改序列中元素的顺序,因此示例序列中没有子序列[37]]

  • 我们有长度为4的递增子序列,即1578,但没有长度为5的子序列,因此我们考虑最长的递增子序列的长度= 4。

输入

a 1 a 2 ... a N (序列)

所有数字都是小于10的正整数3
N <= 1000

输出

一个整数,表示输入序列最长的递增子序列的长度。

sample input(1)
1 2 4 2 5
sample output(1)
4

sample input(2)
1 5 7 1 8 4 3 5
sample output(2)
4

您的代码应及时运行,请在这种情况下测试您的代码,然后在此处提交(此链接还包含我的290字节c ++ 11解决方案)

您可以从文件/标准输入中获取输入,也可以将其作为函数参数使用,也可以将输出打印到文件/标准输出中,或者在编写函数时仅返回值

计分板

  1. 丹尼斯·贾姆-22
  2. 伊萨克·佩斯-26
  3. 霍华德·高夫尔夫特-35
  4. 骄傲的哈斯克勒·哈斯克尔-56
  5. Python 3-66
  6. 历史学家红宝石-67
  7. DLeh C# - 92
  8. 优胜美地马克Clojure- 94
  9. faubiguy Python的3 - 113

1
“我们有1个长度为0的子序列[会认为它正在增加]”,从技术上讲,您有无限个0长度的子序列:)
Cruncher 2014年

实际上,我必须更改该语句,以便所有“集合”都必须删除重复项,例如{1,5,7,1,8,4,3,5}应该为{1,5,7,8,4 ,3},然后我们可以说“集合”中有1个0长度的子序列。谢谢
Mostafa 36a2 2014年

1
对于函数,我们应该计算外部函数(function f(){...})或内部函数(just ...)的字节数吗?如果我们计算外部函数,是否允许匿名函数?
丹尼斯

我们计算外部函数的数量,并允许使用匿名函数,但不要错过提供一个可测试的版本(具有输入/输出处理的完整版本)
Mostafa 36a2

Answers:


2

CJam,22个字节

1e3,q~{_2$<$0=(t}/$0=z

在线尝试。

$ cjam subsequence.cjam <<< '[2 1]'; echo
1
$ cjam subsequence.cjam <<< '[1 9 2 4 3 5]'; echo
4

0.25秒后,程序57为此测试用例打印。

这个怎么运作

我从@Ray的答案中获得了总体思路。

1e3,    " Push the array [ 0 ... 999 ] (J).        ";
q~      " Read from STDIN and evaluate.            ";
{       " For each integer (I) of the input array: ";
  _2$<  " Push [ J[0] ... J[I - 1] ] (A).          ";
  $0=(  " Compute min(A) - 1.                      ";
  t     " Update J[I] with the value on the stack. ";
}/      "                                          ";
$0=     " Compute abs(min(J)).                     ";

5

Python 3、66

请注意,所有数字都在[1,999]范围内,我们可以使用数组b来维护以每个数字结尾的最长子序列长度。b[x] = d表示以结尾的最长子序列x具有length d。对于输入中的每个数字,我们使用来更新数组b[x] = max(b[:x]) + 1,然后max(b)最后完成任务。

时间复杂度是 上) O(mn),其中m始终为1000,n是输入元素的数量。

def f(a):
 b=[0]*1000
 for x in a:b[x]=max(b[:x])+1
 return max(b)

哇,看起来已经没有问题了:)您可以使用stdin / stdout通过添加一行来对其进行测试:

print(f(map(int,input().split())))

for x in a: max(b)看起来几乎是O(n ^ 2)。
霍华德

@Howard O(1000 n)和1000是一个常数。您也可以将其视为O(m n)

3
有了这样的论点,整个讨论是没有用的,因为在有限的输入下,复杂性总是O(1);-)
Howard

@Howard我来自ACM-ICPC领域,在这里有点惯例。您可以将其视为O(mn)。它仍然不同于O(n ^ 2)。无论如何,它所花费的时间将少于解释器的启动时间,因此我认为它足够快。

令人印象深刻的短算法!我只能发现一个字符(至少在切换到Python 2时):您可以打印结果。print比短return
Falko 2014年

3

Python-113

a=[]
for i in map(int,input().split()):
 if not a or i>a[-1]:a+=[i]
 z=0
 while a[z]<i:z+=1
 a[z]=i
print(len(a))

接受的解决方案。您的代码已在此处此处经过测试。
Mostafa 36a2

@ Mostafa36a2“已接受”一词在此站点上还有另一个含义。我认为您的意思是“可以接受的”。

抱歉,是的,我的意思是接受,还为时过早选择接受的。
Mostafa 36a2

使用行a+=[i]*(a==[]or i>a[-1]);z=0和打印len(a)(不带括号),您可以保存4个字符。
Falko 2014年

3

Pyth,26 29 33 39

J*]0^T3Fkyw=@JkheS:J0k)eSJ

@ray解决方案的端口。通过官方测试。现在使用以空格分隔的STDIN输入,而不是函数调用。

运行如下:

./pyth.py -c "J*]0^T3Fkyw=@JkheS:J0k)eSJ" <<< "1 5 7 2 8 4 3 5"
4

说明:

J*]0^T3                 J = [0]*10^3
Fkyw                    For k in space_sep(input()):
=@Jk                    J[k]=
heS:J0k                 max(J[0:k])+1
)                       end for
eSJ                     max(J)

时间无限制:

珀斯 18岁

L?eS,ytbhyf>Thbbb0

技术说明:撰写本文时,我发现Pyth编译器中存在错误。L没有工作。这就是为什么最近对上述git存储库进行了提交。


您的代码不适用于列表较大(例如100个元素)的案例,不能及时运行
Mostafa 36a2 2014年

3
@ Mostafa36a2如果您需要运行时,请在问题中这样说,然后添加一个或两个测试用例。如果只是评论,那我同意,这很慢。
isaacg 2014年

对不起,但是我已经提到这不是运行时,而是至少是一种[及时的方式],如果代码需要10-20分钟甚至一个小时,就没有问题,但是O(2 ^ n)解决方案将永远不会给出结果我们的长寿。
Mostafa 36a2 2014年

@ Mostafa36a2知道了,我只是注意到那条线。我会进行改进。
isaacg

1
对不起,我现在看到更新了,请尝试这种情况并告诉我是否可行。
Mostafa 36a2

3

Clojure,94个字符

使用@Ray的更新方法可得出1000项向量:

(defn g[s](apply max(reduce #(assoc % %2(inc(apply max(take %2 %))))(into[](repeat 1e3 0))s)))

根据请求,带有打印语句(将打印答案并返回nil)。输入应为向量(g [1 2 3])或列表(g'(1 2 3)):

(defn g[s](prn(apply max(reduce #(assoc % %2(inc(apply max(take %2 %))))(into[](repeat 1e3 0))s))))

您可以添加打印语句以使其可测试吗?它不会计入分数。
Mostafa 36a2 2014年

1
更新。我已经在您的两个大型示例上运行过,并且得到了预期的58和57。
YosemiteMark

我认为您仍然需要调用函数:p,但是如果您已经测试过,那就足够了。
Mostafa 36a2

3

Haskell,58 57 56个字符

(x:s)%v|v>x=x:s%v|0<1=v:s
_%v=[v]
l s=length$foldl(%)[]s

这使用了我曾经在互联网上见过的算法,但是我找不到它。在使用GHCi的计算机上,给定测试用例花费的时间非常少(如果经过编译,可能会更快)。


您提到的算法与@faubiguy使用的算法相同。
2014年

@Ray你说得对
骄傲的haskeller 2014年

2

GolfScript,35个字符

~]]){1${~2$<*)}%1+$-1>[\+]+}/$-1=0=

一个实现为完整程序的实现,在STDIN上输入(没有给出长度编号)。即使是较长的输入,该实现也是合理的快速(请在此处尝试)。

例子:

> 1 5 7 1 8 4 3 5
4

> 5 1 9 9 1 5
2

1
@MartinBüttner我的计算机上的1000个号码大约需要5秒钟。假设$为O(n log n),则算法为O(n ^ 2 log n)。
霍华德


@ Mostafa36a2我已经做过(请参阅前面的评论)。5秒后返回58
霍华德

这是另外一个,它应该返回57,所以如果你的代码真的回来了57则的接受:)恭喜
穆斯塔法36A2

@ Mostafa36a2啊,现在我看到了这是两个不同的测试案例。是的,您的第二个链接返回57,就像我对此输入的解决方案一样。
霍华德

2

Ruby,67岁

s=Hash.new{|s,a|f,*r=a
s[a]=f ?[1+s[r.select{|x|x>f}],s[r]].max: 0}

这在大型输入上需要30秒,这是否应该及时计入?:p

这是蛮横的递归,但带有一些记忆。


1
是的,这是一种及时的方式:)
Mostafa 36a2

2

C#,172 92个字符

没什么特别的,但是我做到了,所以我认为我也可以提交。

int a(int[] j){int c=2,m=2,i=1;for(;++i<j.Length;){c=j[i]>j[i-1]?c+1:2;m=c>m?c:m;}return m;}

感谢Armin和Bob的改进!


1
您可以将参数更改为int [],然后字符较少,因为您无需将字符串
Armin 2014年

2
周围的空间=>是不必要的。您也可以将i=0声明移到for循环外int c=2,m=2,i=0;for(;。您也可以将括号放在for身体周围,因为那里只有一条语句。
鲍勃

并且c++;if(c>m)m=c;可以是m=c++>m?m:c;,然后您可以再次将花括号放到该位置。
鲍勃

1
事实上,你也可以放弃if(i>0)通过使检查for循环开始在1.您可以进一步缩短int c=2,m=2,i=0;for(;i<j.Length;i++)if(i>0)建议更早的进入int c=2,m=2,i=0;for(;i++<j.Length;)。整个部分都可以转换为int c=2,m=2,i=0;for(;i++<j.Length;){c=j[i]>j[i-1]?c+1:2;m=c>m?m:c;}(使用另一个三进制替换最后剩余的if-如果您的if身体只是一个任务,则经验法则是三进制较短。)
Bob

2
抱歉,我之前的评论中m=c>m?m:c应该有错别字m=c>m?c:m。如果加上@Armin的建议,您将获得92个字节,几乎减少了一半!int a(int[] j){int c=2,m=2,i=0;for(;i++<j.Length;){c=j[i]>j[i-1]?c+1:2;m=c>m?c:m;}return m;}
鲍勃

2

J,19个字节

[:#]`I.`[} ::,~/@|.

在线尝试!

使用修改后的耐心排序以O(n log n)运行,因为只需要长度,而不需要实际的子序列。

说明

[:#]`I.`[} ::,~/@|.  Input: array
                 |.  Reverse
               /     Reduce right-to-left
     I.                Find the index to insert while keeping it sorted
                       (uses binary search)
         }             Amend the current search array at that index with the next value
           ::          If error (when the index is not found)
             ,           Append the value at the end
 #                   Length of that array

1

Bash + coreutils,131个字节

该解决方案在及时性要求上严重失败,并且并不是特别短,但是我喜欢这种事情至少在理论上可以在Shell脚本中实现,所以无论如何我都会发布。这以O(2 ^ n)的永恒诱导时间复杂度运行。

s=${1//,/,:\},\{}
a=`eval echo "{$s,:}"`
for s in $a;{
b="$(tr , \\n<<<$s|grep -v :)"
sort -nC<<<"$b"&&wc -w<<<$b
}|sort -nr|sed 1q

输入是一个逗号分隔的列表,作为单个命令行参数传递:

$ time ./slisc.sh 1,5,7,1,8,4,3,5
4

real    0m1.240s
user    0m0.518s
sys 0m0.689s
$ 

括号扩展用于构建所有可能的子序列的列表。

  • 第一行用替换逗号,:},{,这会产生类似1,:},{5,:},{7,:},{1,:},{8,:},{4,:},{3,:},{5
  • 第二行使用大括号,逗号和分号来完成此字符串,以提供此功能{1,:},{5,:},{7,:},{1,:},{8,:},{4,:},{3,:},{5,:}。这是有效的bash括号扩展,当eval与一起使用时echo会产生此空格分隔的列表1,5,7,1,8,4,3,5 1,5,7,1,8,4,3,: 1,5,7,1,8,4,:,5 1,5,7,1,8,4,:,: ...
  • 默认情况下,bash用空格分割字符串,因此我们遍历此列表的每个元素:
    • 用逗号替换换行符,然后删除包含冒号的行,为每个可能的子序列提供换行符分隔的列表
    • 然后sort -C,我们测试递增顺序,如果是,则使用它wc -w来打印列表的长度
  • 结果列表长度的列表将反向排序,并打印出第一个值以给出最长的子序列长度。

1

Stax,21 个字节

ë/NS7Γ╥╚┌{1╤╒¬è¶²╢╦┌☼

运行并调试

它有两个测试用例,其中一个是1000个元素的用例。它在我的机器上每24秒运行一次。对于这种类型的问题,它使用经典的动态编程方法。


0

J 34

请注意,我也阅读标准输入。

>./;+/@:*&.>(<*>.)/\&.><\.".1!:1]3

如果不阅读标准输入内容,则该内容为26个字符。

>./;+/@:*&.>(<*>.)/\&.><\.

刚注意到我的大输入运行速度很慢,哦。



0

C#(.NET Core),155字节

使用数组来计算最长的递增子序列,该序列在输入数组的每个位置处终止(动态编程),然后返回最大值。例如,对于输入所计算的阵列[1,5,7,1,8,4,3,5]将是[1,2,3,1,4,2,2,3],而最大的值4被返回。

int b(int[]x){int l=x.Length,r=1,i=0,j,c;var a=new int[l];a[0]=1;while(++i<l)for(j=0;j<i;j++){c=x[j]<x[i]?a[j]+1:1;a[i]=a[i]<c?c:a[i];r=r<c?c:r;}return r;}

在线尝试!


0

Wolfram语言(Mathematica),38个字节

Length@LongestOrderedSequence[#,Less]&

在线尝试!

当然,内置Mathematica可以找到最长的有序序列。它的名字很长:它占解决方案的一半以上,如果有人将解决方案付诸实践,我也不会感到惊讶。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.