find largest submatrix algorithm

前端 未结 2 992
暖寄归人
暖寄归人 2021-02-09 13:24

I have an N*N matrix (N=2 to 10000) of numbers that may range from 0 to 1000. How can I find the largest (rectangular) submatrix that consists of the same number?

Exampl

2条回答
  •  旧时难觅i
    2021-02-09 14:09

    This is a work in progress

    I thought about this problem and I think I may have a O(w*h) algorithm.

    The idea goes like this:

    • for any (i,j) compute the highest number of cells with the same value in the column j starting from (i,j). Store this values as heights[i][j].
    • create an empty vector of sub matrix (a lifo)
    • for all row: i
      • for all column: j
        • pop all sub matrix whose height > heights[i][j]. Because the submatrix with height > heights[i][j] cannot continue on this cell
        • push a submatrix defined by (i,j,heights[i][j]) where j is the farest coordinate where we can fit a submatrix of height: heights[i][j]
        • update the current max sub matrix

    The tricky part is in the inner loop. I use something similar to the max subwindow algorithm to ensure it is O(1) on average for each cell.

    I will try to formulate a proof but in the meantime here is the code.

    #include 
    #include 
    #include 
    #include 
    #include 
    
    typedef std::vector   row_t;
    typedef std::vector matrix_t;
    
    std::size_t height(matrix_t const& M) { return M.size(); }
    std::size_t width (matrix_t const& M) { return M.size() ? M[0].size() : 0u; }
    
    std::ostream& operator<<(std::ostream& out, matrix_t const& M) {
      for(unsigned i=0; i(out, ", "));
        out << std::endl;
      }
      return out;
    }
    
    struct sub_matrix_t {
      int i, j, h, w;
      sub_matrix_t(): i(0),j(0),h(0),w(1) {}
      sub_matrix_t(int i_,int j_,int h_,int w_):i(i_),j(j_),h(h_),w(w_) {}
      bool operator<(sub_matrix_t const& rhs) const { return (w*h)<(rhs.w*rhs.h); }
    };
    
    
    // Pop all sub_matrix from the vector keeping only those with an height
    // inferior to the passed height.
    // Compute the max sub matrix while removing sub matrix with height > h
    void pop_sub_m(std::vector& subs,
               int i, int j, int h, sub_matrix_t& max_m) {
    
      sub_matrix_t sub_m(i, j, h, 1);
    
      while(subs.size() && subs.back().h >= h) {
        sub_m = subs.back();
        subs.pop_back();
        sub_m.w = j-sub_m.j;
        max_m = std::max(max_m, sub_m);
      }
    
      // Now sub_m.{i,j} is updated to the farest coordinates where there is a
      // submatrix with heights >= h
    
      // If we don't cut the current height (because we changed value) update
      // the current max submatrix
      if(h > 0) {
        sub_m.h = h;
        sub_m.w = j-sub_m.j+1;
        max_m = std::max(max_m, sub_m);
        subs.push_back(sub_m);
      }
    }
    
    void push_sub_m(std::vector& subs,
            int i, int j, int h, sub_matrix_t& max_m) {
      if(subs.empty() || subs.back().h < h)
        subs.emplace_back(i, j, h, 1);
    }
    
    void solve(matrix_t const& M, sub_matrix_t& max_m) {
      // Initialize answer suitable for an empty matrix
      max_m = sub_matrix_t();
      if(height(M) == 0 || width(M) == 0) return;
    
      // 1) Compute the heights of columns of the same values
      matrix_t heights(height(M), row_t(width(M), 1));
      for(unsigned i=height(M)-1; i>0; --i)
        for(unsigned j=0; j subs;
      for(int i=height(M)-1; i>=0; --i) {
        push_sub_m(subs, i, 0, heights[i][0], max_m);
        for(unsigned j=1; j

提交回复
热议问题