【问题标题】:Matrix largest product of n numbers in a row矩阵连续n个数字的最大乘积
【发布时间】:2014-02-27 17:58:56
【问题描述】:

您好,我在尝试编写一个小程序时遇到了问题。问题是,如果我给定任何矩阵大小(假设这个例子是 4x4),找到一行中 n 个数字的最大乘积(假设 n = 3)。一行中的 3 个数字可以是水平的、垂直的或对角线。所以这里有一个矩阵:

1 1 2 5
1 5 2 4
1 7 2 3
1 8 2 1

如果 n 等于 3,那么我的最大乘积将是 280 (5*7*8)。现在我将矩阵加载到二维向量中。我对程序的工作方式不太挑剔(蛮力很好),到目前为止,我知道我必须至少有两个嵌套的 for 循环才能通过矩阵的每个凝视位置,但我没有成功地找到了当前的答案。任何建议都会有所帮助,谢谢。

【问题讨论】:

  • 行或列中的数字只能相邻或n的任意组合?
  • 相邻,必须是n个连续的数字(而不是矩阵的一行)

标签: c++ math matrix computation


【解决方案1】:

使用滚动乘法以节省一些资源的方式在行中查找最大产品的版本。这个滚动过程意味着我们不必乘以 n 值来找到这些 n 值的每个乘积,而是只需要执行 one 乘法和 one 除法:

if (currN == N) { // compute full product first time
    while (currn) {
         product *= (*it3++);
          --currn;
    }
 } else {          // rolling computation
     product *= (*(it3 + n - 1)) / (*(it3 - 1));
     it3 += n;
 }

您也可以完成此操作以处理列:

填充矩阵:

#include <cstdio>
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;

typedef vector< vector< int> > Matrix;
typedef Matrix::iterator outIt;
typedef vector< int>::iterator inIt;

void fillMatrix( Matrix& matrix) {
    outIt it = matrix.begin();
    (*it).push_back( 1);
    (*it).push_back( 1);
    (*it).push_back( 2);
    (*it).push_back( 5);
    ++it;
    (*it).push_back( 1);
    (*it).push_back( 5);
    (*it).push_back( 2);
    (*it).push_back( 4);
    ++it;
    (*it).push_back( 1);
    (*it).push_back( 7);
    (*it).push_back( 2);
    (*it).push_back( 3);
    ++it;
    (*it).push_back( 1);
    (*it).push_back( 8);
    (*it).push_back( 2);
    (*it).push_back( 1);
}

打印矩阵并在行中找到最大产品:

void printMatrix( Matrix& matrix) {
    outIt it = matrix.begin();
    while ( it != matrix.end()) {
        inIt it2 = (*it).begin();
        while ( it2 != (*it).end()) {
            printf( "%d", *it2);
            ++it2;
        }
        printf( "\n");
        ++it;
    }
}

/**
 * 
 * @param matrix
 * Largest product in row using rolling multiplication
 * @param n number of factors
 * @param v factors of largest product
 * @return largest product
 */
int largestProductInRow( Matrix& matrix, int n, vector< int>& v) {
    if ( n > matrix.size()) return -1;
    int res = 0;
    int N = matrix.size() - n + 1; // number of products in row (or column)
    /* search in rows */
    outIt it = matrix.begin();
    while (it != matrix.end()) {
        inIt it2 = (*it).begin();
        int currN = N;
        int product = 1;
        while (currN) {       // rolling product calculation
            inIt it3 = it2;
            int currn = n;
            if (currN == N) { // compute full product first time
                while (currn) {
                    product *= (*it3++);
                    --currn;
                }
            } else {          // rolling computation
                product *= (*(it3 + n - 1)) / (*(it3 - 1));
                it3 += n;
            }
            if (product > res) {
                res = product;
                copy(it3 - n, it3, v.begin());
            }
            --currN;
            ++it2;
        }
        ++it;
    }
    return res;
}

用法:

/*
 * 
 */
int main(int argc, char** argv) {

    Matrix matrix( 4, vector< int>());
    fillMatrix( matrix);
    printMatrix( matrix);
    vector< int> v(3);
    int res = largestProductInRow( matrix, 3, v);
    printf( "res:%d\n", res);
    copy( v.begin(), v.end(), ostream_iterator<int>(cout, ","));
    return 0;
}

结果:

分辨率:42

7,2,3,

运行成功(总时间:113 毫秒)

【讨论】:

    【解决方案2】:

    假设我们有 s x t 矩阵(s 列和 t 行)。

    int res = 0;
    if(s >= n)
    {
        for (int r = 0; r < t; ++r) // for each row
        {
            for (int i = 0; i <= s-n; ++i)  //moving through the row
            {
                int mul = m[i][0];
                for (int j = 1; j < n; ++j) //calculating product in a row
                {
                    mul*=m[i][j];
                }
                if(mul > res)
                {
                    res = mul;
                    //save i, j here if needed
                }
            }   
        }
    }
    
    
    if(t >= n)
    {
        for (int c = 0; c < s; ++c) // for each column
        {
            for (int i = 0; i <= t-n; ++i)  //moving through the column
            {
                int mul = m[0][i];
                for (int j = 1; j < n; ++j) //calculating product in a column
                {
                    mul*=m[j][i];
                }
                if(mul > res)
                {
                    res = mul;
                    //save i, j here if needed
                }
            }   
        }   
    }
    

    【讨论】:

      【解决方案3】:

      如果你坚持蛮力,那么正如你所说,你需要遍历所有[x,y], 这将是行的起点。 从这些您可以在所有方向上迭代k 相邻元素。 您可以将方向作为向量存储在数组中。 这将在O(k n^2) 中运行。

      对于n x n 矩阵并在行中查找k 元素,类似C 的伪代码如下所示(注意,为简单起见,没有边界检查):

      // define an array of directions as [x,y] unit vectors
      // you only need to check in 4 directions, other 4 are the same, just reversed
      int[4][2] dirs = {{1,0}, {1,1}, {0,1}, {-1,1}};
      
      // iterate over all starting positions
      for (x = 0; x < n; ++x) {
          for (y = 0; y < n; ++y) {
              // iterate over all directions
              for (d = 0; d < 4; ++d) {
                  result = 1;
                  // iterate over elements in row starting at [x,y]
                  // going in direction dirs[d]
                  for (i = 0; i < k; ++i) {
                      // multiply current result by the element,
                      // which is i places far from the beginning [x,y]
                      // in the direction pointed by dirs[d]
                      new_x = x + i * dirs[d][0];
                      new_y = y + i * dirs[d][1];
                      // you need to check the bounds, i'm not writing it here
                      // if new_x or new_y are outside of the matrix
                      // then continue with next direction
                      result *= matrix[new_x][new_y];
                  }
                  if (result > max) {
                      max = result;
                  }
              }
          }
      }
      

      稍微好一点,不那么暴力的方法是 从矩阵的边界开始,选择一个方向,然后沿着这个方向走到矩阵的另一侧,同时保持最后一个k 数字的乘积。

      在走路时,你保留产品,将它乘以你得到的数字,然后除以你离开k几步前的数字。 这样,当然有一些边界检查, 该产品始终是最后一个 k 数字的产品, 因此,如果当前产品超过最大值,就让max = product。 这始终在O(n^2) 中运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-15
        • 2014-10-21
        • 2021-03-09
        • 1970-01-01
        • 1970-01-01
        • 2013-03-31
        相关资源
        最近更新 更多