选择前缀数最多的索引?

时间:2018-08-01 01:35:56

标签: c++ algorithm stdvector prefix

我有多个0和1的序列,我想找到一个具有最大数量其他序列的序列,这些序列构成当前序列的前缀。

示例:

std::vector<std::vector<int>> sequence={{1,1},{1},{0,1,0,1},{1,1,0}}

{1,1}仅具有1个前缀,即{1}。

但是{1,1,0}有2个前缀{1,1}和{1}。由于它的前缀数最多,因此我想选择sequence.的索引3,我可以使用嵌套循环来完成,但是由于要处理大小为 512 。感谢您的帮助。

到目前为止我所做的:

bool isPrefixOf(std::vector<int> current, std::vector<int> other){
  if (other.size()>current.size())
      return false;
  for (int i=0; i<other.size(); ++i) {
      if (other[i] != current[i]) 
          return false;
    }
  return true; 
}

int len = sequence.size();
int max = 0;
int selected = -1;
int prefix_count;
for(int i=0; i<len; i++){
    prefix_count = 0;
    for(int j=0; j<len; j++){
      if(isPrefixOf(sequence[i],sequence[j])) ++prefix_count;
    }
    if(prefix_count >= max){
      max = prefix_count;
      selected = i;
    }
  }

1 个答案:

答案 0 :(得分:2)

您的双循环结果为O(n 2 )算法。如果您按照以下方式构建prefix tree(在您的情况下为二进制),则可以获得O(n):

  • 对于每个单个序列,请遍历值,并在0左边的孩子和1右边的孩子。如果不存在,则创建新的孩子。
  • 如果序列完成,则增加当前节点(无论是否叶子!)。变体:如果您不希望计算重复项,只需将节点值设置为1(是否在此之前)。
  • 仅叶子是有趣的,因为任何父节点都与叶子共享前缀,但本身是前缀,因此叶子将(至少)再有一个前缀。
  • 对于每个叶子,对从根到叶子的路径上的值求和。
  • 具有最大数量的叶子标志着您要遵循的顺序;您可以在计算总和时记住最大权利,所以您不必两次走树

对于您给定的示例,树看起来像这样:

      [0] (root, always 0)
     /   \
    /(0)  \(1)
   /       \
 [0]       [1] (one sequence finished here!)
   \         \
    \(1)      \(1)
     \         \
     [0]       [1]
     /          /
    /(0)       /(0)
   /          / 
 [0]        [1]<3>
   \
    \(1)
     \
     [1]<1>

将叶子包括在总和中将正确地考虑叶子中的重复项。这将包括形成离开自身的路径的序列(解释:每个序列都是其自身的前缀),但是对于 every 叶子来说,对于所有同等叶子,您得到的偏移量均为1 ,因此这不会影响您追求的最大值...

您可能还需要在原始向量中存储通向该节点内部节点的序列的索引,以便更快地进行访问。