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

时间:2016-07-24 20:42:21

标签: c++ arrays matrix multidimensional-array

打印唯一的行号。

以下是我的实施:

#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(行*列);因为每行都会访问每个列元素。

这是最佳的运行时间吗?

2 个答案:

答案 0 :(得分:2)

您的方法似乎有问题:

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

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

您应该使用unsigned long的{​​{1}}类型来解决此问题,保证至少有32位,tracker已定义且值(1UL << value)0不同}}

复杂度确实是 O(rows * cols),但算法固有地限于31,因此当cols <= 5无法增长时很难谈论复杂性任意。

此外,使用cols计算二进制值的效率非常低。

这是一个更简单的版本:

pow(2, i)

答案 1 :(得分:1)

代码中最慢的部分是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;    
}

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

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

更紧凑的方式:

// 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;
    }
}