有趣的數組

螺旋矩陣

對一個如下所示的矩陣
這裏寫圖片描述
規律是從首座標開始依次螺旋增大

很多面試題都喜歡問這樣的問題,解決的方法很簡單,把複雜的問題分解成簡單的問題。
①把一個矩陣分層,一層一層的解決;
②再分層的基礎上,再將一層分成上下左右四個部分單獨解決;
只要注意一下數組的邊界即可循環完成,有一點需要注意當數組的大小爲奇數或是偶數時是有稍許不同的需要注意一下。

#include <iostream>
#include <iomanip>
int main()
{
    using namespace std;
    cout << "Enter the size of matrix: ";
    int n,m=1;
    cin >> n;                   //輸入矩陣的大小
    int **arr = new int*[n];    //動態分配二維矩陣
    if (NULL==arr)              //檢測分配是否成功
    {
        exit(1);
    }
    for (int i = 0; i < n; i++)
    {
        arr[i] = new int[n];
        if (NULL == arr[i])
        {
            exit(1);
        }
    }
    for (int i = 0; i < ((n % 2 != 0) ? (n - 1) / 2:n/2); i++)//對奇偶不同的數組分別計算層數
    {
        for (int j = i; j < n-i-1; j++)     //處理上面
        {
            arr[i][j] = m++;
        }
        for (int j = i; j <n-i-1; j++)      //處理右面
        {
            arr[j][n - i - 1] = m++;
        }
        for (int j = n-i-1; j > i; j--)     //處理下面
        {
            arr[n - i - 1][j] = m++;
        }
        for (int j = n-i-1; j>i; j--)       //處理左面
        {
            arr[j][i] = m++;
        }
    }
    if (n%2!=0)                             //若是奇數,補出中心點
    {
         arr[n / 2][n / 2] = m;
    }

   for (int i = 0; i < n; i++)              //循環打印
    {
        for (int j = 0; j <n; j++)
        {

            cout <<left<<setw(4)<< arr[i][j];
        }
        cout << endl;
    }
   for (int i = 0; i < n; i++)               //釋放二維數組
   {
       delete[] arr[i];
   }
   delete[] arr;

    cin.get();
    cin.get();
    return 0;
}

輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 則依次打印出數字1,2,3,4,8,12,11,10,9,5,6,7
若果要處理的不是一個一直正方形的而是一個長方形的話上面的方法就比較難處理了,因此只需要稍作修改即可

vector<int> printMatrix(vector<vector<int> > matrix) 
    {
     int row = matrix.size();
        int col = matrix[0].size();
        vector<int> res;

        // 輸入的二維數組非法,返回空的數組
        if (row == 0 || col == 0)  return res;

        // 定義四個關鍵變量,表示左上和右下的打印範圍
        int left = 0, top = 0, right = col - 1, bottom = row - 1;
        while (left <= right && top <= bottom)
        {
            // left to right
            for (int i = left; i <= right; ++i)  res.push_back(matrix[top][i]);
            // top to bottom
            for (int i = top + 1; i <= bottom; ++i)  res.push_back(matrix[i][right]);
            // right to left
            if (top != bottom)
            for (int i = right - 1; i >= left; --i)  res.push_back(matrix[bottom][i]);
            // bottom to top
            if (left != right)
            for (int i = bottom - 1; i > top; --i)  res.push_back(matrix[i][left]);
            left++,top++,right--,bottom--;
        }
        return res;
    }

再來看一個神奇的數組zigzag
在JPEG圖像處理算法中首先對圖像進行分塊,會使用到這個“之”字矩陣,它長成下面這個樣子
這裏寫圖片描述

它就像一個蛇一樣,一直在沿着對角線繞,一下增加,一下減小很難實現啊,還是一部分一部分來分析。
我們先單獨來看看左上部分
這裏寫圖片描述
這裏我們要注意到一件事情,zigzag數組的基本變換單位和普通矩陣不一樣,不在是按行或是列變化了,也就是說行數和列數都是變換的,但是在一條斜線上有個關鍵的性質,橫縱座標之和是相等的,這將成爲搞定這個zigzag的突破點。

將每斜開始增長的第一個點叫做跳變點(可能在第一行也可能在第一列,例如1、3、6),那麼就會發現跳變點的值等於,在該點之前的元素的個數,比如上圖中6這個跳變點,它就等於在它之前的元素的個數6,而6對應的座標爲(0,3)對於座標和S=i+j=3,而它之前的元素
sum=1+2+3=S(S+1)/2

我們解決了一個斜行的初始值的問題,接下來就是要確定一個斜行內的元素是從左下到右上的還是從右上到左下的,其實很好分別,因爲是交替出現,利用S的奇偶性即可判斷:
①若S爲奇數,則是從右上至左下的;
②若S爲偶數,則是從左下至右上的;

最後確定準確的數值
我們以(1,2)點爲例,我們已經知道它所在斜的初始值爲6,並是按照從右上到左下遞增的,那麼我們只需要知道它的縱座標是幾就是增加了幾,因此在左上部分值與座標的對應關係可以寫作

arr[i][j] = s*(s + 1) / 2 + (((i + j) % 2 == 0) ? j: i);

接下來看看右下角
這裏寫圖片描述

因爲結構變了 跳轉點(13)就無法通過
sum=1+2+3=S(S+1)/2
計算了,因此我們不找跳轉點了反過來找結束點(12,14)利用這個點反過來算各點的值。

這裏可以將最後一個點當成(0,0)點,會比較好理解

s = (n - 1 - i) + (n - 1 - j);
arr[i][j] = squa - s*(s + 1) / 2 - (n - (((i + j) % 2 == 0) ? j : i));

這樣就完成了

#include <iostream>
#include <iomanip>
int main()
{
    using namespace std;
    int n;
    int s, i, j;
    int squa;
    cout << "Enter the size of matrix: ";
    cin >> n;
    int **arr = new int*[n];            ////動態分配二維矩陣
    if (NULL==arr)
    {
        exit(1);
    }
    for (int i = 0; i < n; i++)
    {
        arr[i] = new int[n];
        if (NULL==arr[i])
        {
            exit(1);
        }
    }
    squa = n*n;
    for  (i = 0; i < n; i++)
    {
        for (j = 0; j < n;j++)
        {
            s = i + j;                         //確定是第幾斜行
            if (s<n)                           //左上部分
            {
                arr[i][j] = s*(s + 1) / 2 + (((i + j) % 2 == 0) ? j: i);
            }
            else                               //右下部分
           {
                s = (n - 1 - i) + (n - 1 - j);
                arr[i][j] = squa - s*(s + 1) / 2 - (n - (((i + j) % 2 == 0) ? j : i));
           }
        }
    }
    //
    for (int i = 0; i < n; i++)                 //循環打印
    {
        for (int j = 0; j < n; j++)
        {
            cout << left << setw(6) << arr[i][j];

        }
        cout << endl;

    }
    for (int i = 0; i < n; i++)               //釋放二維數組
    {
        delete[] arr[i];
    }
    delete[] arr;


    cin.sync();
    cin.get();
    return 0;
}
發佈了44 篇原創文章 · 獲贊 25 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章