Algorithm 从矩阵中删除列后的唯一行

Algorithm 从矩阵中删除列后的唯一行,algorithm,language-agnostic,Algorithm,Language Agnostic,给出了n行和m列的二进制矩阵n和m最多可为2000 我们需要告诉您,是否可以删除一列,以便剩余矩阵的行是唯一的。 n=3和m=4的示例: 1010 0001 1001 答案是肯定的。我们可以删除第二列,其余的行(110,001,101)将是唯一的 n=4和m=2的示例: 00 01 10 11 答案是否定的。无论我们选择哪一列,行0和0都将保留 IO(m*m*n)暴力算法。我通过删除每一列来检查行的唯一性 你知道更快的算法吗?!编辑:不幸的是,我的解决方案只解决了一半,对不起 我相信,我能在

给出了
n
行和
m
列的二进制矩阵
n
m
最多可为2000

我们需要告诉您,是否可以删除一列,以便剩余矩阵的行是唯一的。

n=3
m=4
的示例:

1010
0001
1001
答案是肯定的。我们可以删除第二列,其余的行(
110
001
101
)将是唯一的

n=4
m=2
的示例:

00
01
10
11
答案是否定的。无论我们选择哪一列,行
0
0
都将保留

IO(m*m*n)暴力算法。我通过删除每一列来检查行的唯一性


你知道更快的算法吗?

!编辑:不幸的是,我的解决方案只解决了一半,对不起

我相信,我能在O(m*n)时间内完成

您可以在n*m时间内创建树。只需逐行进行并更新此结构:

Node{
 int accessed;
 Node nextZero;
 Node nextOne;
}
如果你创建了这棵树,你只需要检查最后一行,如果它的“零”和“一”等于或大于两个或不大于两个


这里有一个可视化的例子,展示了处理两个数字后的效果

你只要一行一行地走,总是从根开始

例如,当开始处理第二行时,从根开始。第二行的数字是“101”。你们取第一个数字,它是“1”,所以你们进入nextOne节点。然后你得到“0”,你就进入了nextZero。然后你得到“1”,它不存在,所以你创建它

毕竟,您只对最深度节点中的“已访问”数感兴趣,如果它们都“已访问”等于1,则它们都是不同的,否则它们不是


伪码

Node{
  int accessed;
  Node nextZero;
  Node nextOne;
}

bool isDistinct(){
  Node root = new Node();
  Node next;
  for (int i=0;i<arr.length;i++){
    Node actual = root;
    for (int j=0;j<arr[i].length;j++){
      if (arr[i][j] == 0){
        next = actual.nextZero;
        if (next == null){
          next = new Node();
          acutal.nextZero = next;
        }
      } else {
        next = actual.nextOne;
        if (next == null){
          next = new Node();
          acutal.nextOne = next;
        }
      }

      actual = next;
      actual.accessed++;
      if ((j == arr[i].length - 1) && (actual >= 2)){
        return false;
      }
    }
  }
  return true;
}
节点{
int访问;
节点nextZero;
节点nextOne;
}
bool isDistinct(){
节点根=新节点();
节点下一步;

对于(inti=0;i,每行代表以10为底的一些数字

  • 我们可以在
    O(n*m)
    中计算所有这些数字
  • 我们将得到一个长度为
    n
    的数组
    a
  • 我们可以创建一个数组
    b
    ,位置
    b[i]
    将是数组
    a
    O(n)
  • 如果我们对一些
    i
    b[i]>1
    ,答案是否定的
  • 不,我们将尝试逐个删除列,这将相应地更改数字。例如,如果我们删除
    k
    th列,我们需要创建数组
    c
    ,它与数组
    b
    具有相同的含义,但没有
    k
    th列。为此,我们初始化
    c[i]=b[i]
    如果
    i=2^k
    那么我们将更新
    c[i-2^k]++
    。如果我们得到
    c[i]>1
    对于一些
    i
    来说,答案是否定的,然后继续下一列。否则答案是肯定的。这可以在
    O(n*m)
    中完成
  • 编辑:

    整个解决方案的复杂度为
    O(n*m)


    因为数字会很大,你可以使用字典将数组
    b
    表示为稀疏数组,对于数字,你可以使用一些用于大数字的库。整个解决方案应该比暴力更快。

    有代码吗?我不明白,或者请再解释一点。你能用一些例子解释一下你的方法吗?什么你不是说NextzerNode和nextOneNode吗?不幸的是,它并不总是起作用,反例:
    00,01,10,11
    。但是聪明,我喜欢它。@AdamStelmaszczyk-当然是这样,如果你输入了
    00,01,10,11
    ,你最终会得到根节点,深度1的2个节点和深度2的4个节点。深度2的所有4个节点都有
    访问权限ed
    属性等于1,因此所有列都是不同的。在删除列之前,您是否假设行是唯一的?如果可能,您是否需要知道要删除哪一列?@user3923424我不想知道要删除哪一列。另外,它们也不是这样的假设,不是您的实现O(mmn*n)?对于每m列,您要检查(m-1)*n矩阵中的行是否唯一。检查行是否每n*(n-1)对行进行一次比较,
    测试[i]==测试[j]
    。但字符串比较是O(m),而不是O(1)。行必须是唯一的,否则任务是不可能的--删除一列不能使两个相同的行不同。根据鸽子洞原理,如果n>2^m也是不可能的。n,m可以达到2000,因此这些数字将非常大。你确定计算它们会达到目的吗?它比我的brut更快吗E、N和M可以达到2000…即使我们在2的基础上考虑数字而不是10,你也不能用<代码>长< /COD>来存储这个数字。无论如何,你的数组B和C都将变大(2 ^ 2000=10 ^ 602)。。您可以使用BigNum库来存储数字,并使用映射而不是数组,但我认为在实践中不会更快,因为与原始算法相比,您的开销将是巨大的。好的,大数字可能是一个问题。我认为与蛮力相比,此解决方案无法更快地获得答案。@codetest thePetar提出的解决方案是使用O(nm).nm操作创建数字,然后使用m个循环(对于每列)进行n次操作。