演算法資料結構面試題——標記陣列在矩陣特徵識別中的應用

鍾超發表於2011-03-08

題目:有一個矩陣(10*10),元素值只能為0或1,現在寫一個函式判斷一下有沒有一行都為1,且有一列都為0(除了該行的這個元素為1外)。現要求程式只需要掃描該矩陣一遍,即可得出結果。

來源:網際網路,據說出自微軟面試題。
解答:
不考慮題目最後一句要求的情況下,最直接的方法如下:
bool F(int [10][10]input)
{
   for(int i=0;i<10;i++)
   {
      int j;
      for(j=0;j<10;j++)
         if(input[i][j]==0) break;
      if(j==10)
      {
         for(int m=0;m<10;m++)
         {
            for(int n=0;n<10;n++)
               if(input[n][m]==1&&n!=i) break;
            if(n==10)
               return true;
         }
      }
   }
   return false;
}
可見,這個演算法在每找到一行元素都是1後,會對整個矩陣進行再掃描,理論上對mxn矩陣操作的時間複雜度為O(mn+mxmxn)=O(mxmxn)。但是考慮到實際情況,肯定是不會到這個上限,但是已經效率很低了。
這時可以考慮,另設一個bool ColAllZero[n]陣列,初始為true。在第二層迴圈中掃描第i行是否都是1時,如果出現該行j列元素為1,即標記ColAllZero[j]為false。
這樣只需兩層迴圈,一次掃描,演算法如下。
bool F(int [10][10]input)
{
   bool ColAllZero[10];
   for(int j = 0; j < 10; j++)
      ColAllZero[j] = true;
   for(int i = 0; i < 10; i++)
   {
      int j;
      for(j=0; j < 10; j++) 
         if(input[i][j] == 0) break;
      if(j < 10) //掃描到[i][j]時發現為0,即不滿足要求
      {
         for(int m = 0; m < j; m++)
            ColAllZero[m] = false; //標記0至j-1列不滿足全0
      }
      else //j為10,即掃描完第i行,該行滿足要求
      {
         for(int m = 0; m < 10; m++)
         {
            if(!ColAllZero[m]) continue;
            for(int n = 0; n < i - 1; i++)
            {
               if(input[n][m] == 1)
               {
                  ColAllZero[m] = false;
                  break;
               }
            }
            if(n != i - 1) continue; //[n][m]不為0,不滿足要求
            //否則,m列的0至i-1行滿足全0要求
            if(i == 9) //滿足要求的行號為第9行,即最後一行
               return true; //識別結束,為[i][m]
            for(int n = i + 1; n < 10; i++) //滿足要求的行在最後一行之上
            {
               if(input[n][m] == 1)
               {
                  ColAllZero[m] = false;
                  break;
               }
            }
            if(n == 10) return true; //第i行第m列滿足要求
         }
      }
   }
   return false;
}
特別注意,雖然該演算法仍是三重迴圈,但分析其時間複雜度就會發現是O(mn),而非O(mmn)或O(mnn)。因為在第二層迴圈中不滿足要求但值為1的元素所在的列都會被ColAllZero標記,這些被標記為false的列在第三重迴圈中不會再被訪問。因此時間複雜度為O(mn)。

-

相關文章