我需要创建一个算法,从列表中提取一个最大可能的子集,其中所有元素都是有序的。此子集可以是非连续的,但必须保留原始列表中的顺序。例如:
test=> create user rdstest login password 'rdstest';
CREATE ROLE
test=> grant connect on database test to rdstest;
GRANT
test=> create user devadmin login password 'devtest';
CREATE ROLE
test=> grant connect on database test to devadmin;
GRANT
test=> grant rdstest to devadmin with admin option;
GRANT ROLE
test=> grant rdstest to devadmin;
GRANT ROLE
test=> create schema authorization rdstest;
CREATE SCHEMA
有人可能会将这个问题改为“我至少必须删除哪些元素,以便对其余列表进行排序”。
我不是在寻找一个实现,而只是为了一个简单算法的想法。 到目前为止,我最好的方法是为每个数字构建一个包含节点的树,并且它们的子项在列表后面都是更大的数字。然后树下的最长路径应该等于已排序的子集。但是,这似乎过于复杂。
背景:这是检查学生在测试中的答案,他们必须按大小订购项目。我想找出他们相对于彼此的权利。
答案 0 :(得分:0)
Scala中的递归实现,带有标准列表函数(size,map,filter,dropWhile,reduce):
def longestClimb (nx: List[Int]) : List[Int] = nx match {
case Nil => Nil
case _ => {
val lix = nx.map (n => n :: longestClimb (nx.dropWhile (_ != n).filter (_ > n)))
lix.reduce ((a, b) => if (a.size > b.size) a else b)
}
}
调用:
scala> val nx = List (1, 2, 8, 3, 6, 4, 7, 9, 5)
scala> longestClimb (nx)
res7: List[Int] = List(1, 2, 3, 4, 7, 9)
Prosa:对于一个空列表,结果是空列表和递归过程的结束。
对于整个列表,每个点都作为起点。让我们看一下6的值。对于6被评估为lx.dropWhile(_!= 6)(其为6,4,7,9,5)的longestClimb,过滤为(_> 6),其将前一样本减少为(7,9),其结果为在列表中(6,7,9)。
这不是最长的列表,而是最长子列表的候选者,但由于只搜索了一个最大的列表,lix.reduce ((a, b) => if (a.size > b.size) a else b)
的偏差会产生另一个长度相等的列表,而{{{ 1}}会产生相等长度的列表(1,2,3,6,7,9)。
为了测量,我们使用这种方法得到了多少,我使用了时序和迭代函数:
lix.reduce ((a, b) => if (a.size >= b.size) a else b)
结果非常有趣:
def timed (name: String) (f: => Any) = {
val a = System.currentTimeMillis
val res = f
val z = System.currentTimeMillis
val delta = z-a
println (name + ": " + (delta / 1000.0))
res
}
val r = util.Random
def testRandomIncreasing (max: Int) : Unit = {
(2 to max).map { i =>
val cnt = Math.pow (2, i).toInt
val l = (1 to cnt).toList
val lr = r.shuffle (l)
val s = f"2^${i}=${cnt}\t${lr}%s"
val res = timed (s) (longestClimb (lr))
println (res)
}
}
有趣的是,最后一步从64到128的值,时间增加了大约40倍。使用另一个随机种子的前测试,导致大约2000的因子,并且花费大约8分钟为2 ^ REPL中有7个值。对于2 ^ 8个元素的测试必须中断,因为在最坏的情况下我不想等待11天的结果。