Algorithm 如何从数字子序列中恢复数字?

Algorithm 如何从数字子序列中恢复数字?,algorithm,math,clojure,Algorithm,Math,Clojure,给定四位数1234,有六个可能的两位数子序列(12、13、14、23、24、34)。给定一些子序列,是否可以恢复原始数字 下面是一些示例数据。每行列出不同6位数字的一些3位子序列(待查找) 编辑:有时解决方案可能不是唯一的(可能有多个数字给出了子序列)。在这种情况下,最好返回其中一个,或者甚至是一个列表。您要做的是找到所有子序列的名称。显然,如果您拥有所有子序列,包括原始编号,则SCS将是您所寻找的。否则就无法保证,但这是一个很好的机会 不幸的是,对于这个问题没有一个好的多项式算法,但是如果你在

给定四位数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
    ),因此我们有两个选择:

    • 0
      拆分为2个节点:

        /-----------\----\
       /             v    v
      0 -> 5 ------> 2 -> 8
             \
              > 0
      
        /-----------\
       /             v
      5 ------> 2 -> 5 -> 8
       \        ^    ^
        \       /    /
         > 0 --------
      
    • 5
      拆分为2个节点:

        /-----------\----\
       /             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是您的原始字符串