Algorithm 如何从数字子序列中恢复数字?
给定四位数1234,有六个可能的两位数子序列(12、13、14、23、24、34)。给定一些子序列,是否可以恢复原始数字 下面是一些示例数据。每行列出不同6位数字的一些3位子序列(待查找)Algorithm 如何从数字子序列中恢复数字?,algorithm,math,clojure,Algorithm,Math,Clojure,给定四位数1234,有六个可能的两位数子序列(12、13、14、23、24、34)。给定一些子序列,是否可以恢复原始数字 下面是一些示例数据。每行列出不同6位数字的一些3位子序列(待查找) 编辑:有时解决方案可能不是唯一的(可能有多个数字给出了子序列)。在这种情况下,最好返回其中一个,或者甚至是一个列表。您要做的是找到所有子序列的名称。显然,如果您拥有所有子序列,包括原始编号,则SCS将是您所寻找的。否则就无法保证,但这是一个很好的机会 不幸的是,对于这个问题没有一个好的多项式算法,但是如果你在
编辑:有时解决方案可能不是唯一的(可能有多个数字给出了子序列)。在这种情况下,最好返回其中一个,或者甚至是一个列表。您要做的是找到所有子序列的名称。显然,如果您拥有所有子序列,包括原始编号,则SCS将是您所寻找的。否则就无法保证,但这是一个很好的机会 不幸的是,对于这个问题没有一个好的多项式算法,但是如果你在谷歌上搜索它,你会发现有很多近似算法可用。例如,其中提到有三种总体方法:
下面是另一篇关于这个问题的好文章:构建一个有向图,每个数字在每个序列中都连接到它后面的数字 处理周期: 一个循环意味着一个不可能的场景-同一个角色不能有两个位置(可以有多个位置的角色具有相同的值,但不是完全相同的角色-作为一个隐喻,可以有许多人叫Bob,但任何给定的Bob只能在一个位置)。某些节点必须拆分为多个节点。应分割所选节点,以便所有传入边位于一个新节点中,所有传出边位于另一个节点中,并且这两个节点之间存在连接 应该有多个节点可以选择进行拆分,可能只有一个是正确的,您可能需要探索所有的可能性,直到找到一个可行的。如果一个不起作用,你会得到一个比下面某个地方允许的更长的字符串 最好是在拓扑排序之前(以相同的方式解析循环)完全消除循环 处理具有相同值的节点(由于周期分辨率): 如果可以选择具有相同值的多个节点,则让传出边从第一个节点(具有指向所有其他节点的路径的节点)和传入边到最后一个节点(所有其他节点具有指向路径的节点)。如果在同一序列中有多个具有相同值的数字,则显然需要稍微修改 查找实际字符串: 若要确定字符串,请在图形上执行一次 示例: 假设我们正在寻找一个5位数字,输入为:
528, 508, 028, 502, 058, 058
我知道058
的复制有点微不足道,但这只是为了举例说明
对于528
,为5
、2
和8
创建节点,并连接5
和2
和2
和8
5 -> 2 -> 8
5 -> 2 -> 8
\ /
> 0
对于508
,创建0
,连接5
和0
和0
和8
5 -> 2 -> 8
5 -> 2 -> 8
\ /
> 0
对于028
,连接0
和2
5 ------> 2 -> 8
\ / /
> 0 -----
对于502
,所有连接都已存在
对于058
,我们得到一个循环(5->0->5
),因此我们有两个选择:
- 将
拆分为2个节点:0
/-----------\----\ / v v 0 -> 5 ------> 2 -> 8 \ > 0
/-----------\ / v 5 ------> 2 -> 5 -> 8 \ ^ ^ \ / / > 0 --------
- 将
拆分为2个节点:5
/-----------\----\ / v v 0 -> 5 ------> 2 -> 8 \ > 0
/-----------\ / v 5 ------> 2 -> 5 -> 8 \ ^ ^ \ / / > 0 --------
058
,我们需要最后一个5
的传出边(在本例中为右侧5
),以及第一个5
的传入边(在本例中为左侧5
)。这些边(5->0
和5->8
)已经存在,因此无需执行任何操作
拓扑排序将为我们提供
50258
,这是我们的编号。让逻辑编程为您完成这项工作
我是维安
定义子序列的含义
(defne subseqo [s1 s2]
([(h . t1) (h . t2)] (subseqo t1 t2))
([(h1 . t1) (h2 . t2)] (!= h1 h2) (subseqo s1 t2))
([() _]))
通过解算器运行约束
(defn recover6 [input-string]
(run* [q]
(fresh [a b c d e f]
(== q [a b c d e f])
(everyg (fn [s] (subseqo (seq s) q))
(re-seq #"\d+" input-string)))))
示例(结果在REPL上是即时的):
在最后一个示例中,下划线表示
\u 0
和\u 1
是自由变量。他们没有受到约束。将任何自由变量约束到一组数字是很容易的。这是什么样的彩虹表?;)我不理解示例数据。有分组吗?@Branimir按行分组。。。我希望如此。第一行中的所有序列都可能是某个未知6位数字的子序列。如果您只需要子序列中的任何数字,您可以简单地将所有输入数字串联起来。如果你需要一个具体的长度,你应该看看下面我的答案。如果我的答案产生了一个太短的解,你可以简单地附加随机数,直到你得到一个足够长的。如果我的答案太长,将很难找到正确的解决方案。对于测试用例“111”“222”“121”,将“必须成对应用”。在第一对之后,你可能会得到“111222”,在第三对之后,你会得到“1112221”,但它错了,因为所有3对可能都用了“121122”。这很公平。它也适用于超弦而不是超序列。我链接到了另一篇论文。这个算法不能保证答案正确。对于被3个子序列拆分的字符串“11121”,您可能会发现“11211”(或更小的大小),但实际上输入数据中不存在字符串“211”,因此“11211”不是正确答案。是的,但假设11121是您的原始字符串