在二进制 2D 数组中查找唯一行

Find the unique rows in Binary 2D array

本文关键字:查找 唯一 数组 二进制 2D      更新时间:2023-10-16

打印唯一的行号。

以下是我的实现:

#include <iostream>
#include <cmath>
int rowsToInt(int m[][5], int row, int cloumLen) {
    int sum = 0;
    // m[row][column]
    for (int i = 0; i < cloumLen; i++) {
        sum += m[row][i]*(std::pow(2,i));
    }
    return sum;
}
void removeDuplicate(int m[][5], int row, int column) {
    if (!m) {
        return;
    }
    int tracker = 0;
    int mask = 1;   
    int value;
    for (int i = 0; i < row; i++) {
        value = rowsToInt(m, i, column); // 3
        if (((mask << (value - 1)) & tracker) == 0) {
            // print unique row
            std::cout << "row: " << i << " is unique" << std::endl;
            // set that bit to 1
            tracker = tracker ^ (mask << (value - 1));
        }
    }
}
int main() {
    int array[5][5] = {
        {0,1,0,0,1},
        {1,0,1,1,0},
        {0,1,0,0,1},
        {1,1,1,0,0},
        {1,1,0,1,1}
    };
    removeDuplicate(array, 5, 5);
    return 0;
}

输出为:

row: 0 is unique
row: 1 is unique
row: 3 is unique
row: 4 is unique

运行时间是多少?我认为它的 O(行*列(;因为每一行然后访问每个列元素。

这是最佳运行时间吗?

您的方法似乎有问题:

  • 函数 rowsToInt 将 5 int 的子数组转换为介于 031 之间的值,假设这些值是严格的二进制(0 或 1(。

  • 在函数 removeDuplicates 中,您可以将这些值用作表达式中的移位计数器: (mask << (value-1))其中mask是值为 1int。这是跟踪到目前为止看到的行的精明方法,但表达式会调用value == 0的未定义行为。

您应该使用unsigned long类型来解决此问题 tracker ,保证至少有 32 位,并且对于0 31的值(1UL << value)定义和不同。

复杂度确实是O(rows * cols(,但算法本质上仅限于cols <= 5,所以当cols不能任意增长时,很难谈论复杂度。

此外,使用 pow(2, i) 计算二进制值的效率非常低。

这是一个更简单的版本:

#include <iostream>
#include <cmath>
int rowsToInt(int m[][5], int row, int cloumLen) {
    int sum = 0;
    // m[row][column]
    for (int i = 0; i < cloumLen; i++) {
        sum += m[row][i] << i;
    }
    return sum;
}
void removeDuplicate(int m[][5], int row, int column) {
    if (!m) {
        return;
    }
    unsigned long tracker = 0;
    for (int i = 0; i < row; i++) {
        int value = rowsToInt(m, i, column); // 3
        if (((1UL << value) & tracker) == 0) {
            // print unique row
            std::cout << "row: " << i << " is unique" << std::endl;
             // set that bit to 1
            tracker |= 1UL << value;        
        }   
    }
}
int main() {
    int array[7][5] = {
        {0,1,0,0,1},
        {1,0,1,1,0},
        {0,1,0,0,1},
        {1,1,1,0,0},
        {1,1,0,1,1},
        {0,0,0,0,0},
        {0,0,0,0,0},
    };
    removeDuplicate(array, 7, 5);
    return 0;
}

代码中最慢的部分是 std::pow() ,对于 200000 行的数组,它将被调用一百万次,这需要相当长的时间,所以不要在不必要的循环中使用它。如果您需要 2 的幂,最快的方法是使用按位旋转,就像@chqrlie一样。一般来说,如果你需要通电N,你可以按如下方式获取它们:

int rowsToInt (bool m[][5], int row, int cloumLen) {
    int sum = 0;
    for (int i = 0, p = 1; i < cloumLen; i++) {
        sum += m[row][i]*p;
        p *= N;
    }
    return sum;    
}

现在进行优化。如果您使用的是二进制矩阵,为什么要使用整数 1?它需要 4 倍的 RAM,因此请使用 bool array[rows][cols] .行数和列数是常量,因此无需将它们传递给函数。您可以只声明全局const int rows = 7, cols = 5。还有一个重要因素。如果您正在大矩阵中搜索唯一的二进制行,则值得计算找到的二进制行。如果您已经找到了其中的 2^col,请离开循环。

您的搜索方法相当复杂。让我展示两种更简单的方法来解决您的问题。

更紧凑的方式:

// the code inside removeDuplicate function
unsigned long tracker = 0; // now it looks like 32 zeros
for (int i = 0; i < row; ++i) {
    int value = rowsToInt (m, i, column); // getting dec value
    if (((tracker >> value) & 1) == 0) { // if the valueth bit is equal to zero
        tracker |= (1UL << value); // set it equal to one
        std::cout << "row: " << i << " is unique" << std::endl;
        if (tracker = 0xffffffff) return; // if all bits are equal to 1, we've found all the unique rows
    }
}

最简单的一个:

// the code inside removeDuplicate function
bool found[32] = {false}; // using array instead of UL
int counter = 0; // and simple counter of unique rows
for (int i = 0; i < row; i++) {
    int value = rowsToInt (m, i, column); // getting dec value
    if (!found[value]) { // if the valueth element is equal to zero
        found[value] = true; // set it equal to one
        ++counter; // and increase the counter
        std::cout << "row: " << i << " is unique" << std::endl;
        if (counter == 32) return;
    }
}