找到最大的已排序子集

时间:2018-04-11 21:24:41

标签: algorithm

我需要创建一个算法,从列表中提取一个最大可能的子集,其中所有元素都是有序的。此子集可以是非连续的,但必须保留原始列表中的顺序。例如:

   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

有人可能会将这个问题改为“我至少必须删除哪些元素,以便对其余列表进行排序”。

我不是在寻找一个实现,而只是为了一个简单算法的想法。 到目前为止,我最好的方法是为每个数字构建一个包含节点的树,并且它们的子项在列表后面都是更大的数字。然后树下的最长路径应该等于已排序的子集。但是,这似乎过于复杂。

背景:这是检查学生在测试中的答案,他们必须按大小订购项目。我想找出他们相对于彼此的权利。

1 个答案:

答案 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天的结果。