螺旋打印矩阵

由外向内螺旋
vector<int> spiralOrder(vector<vector<int>>& matrix) {
    if (matrix.empty()) return {};
    const int R = matrix.size(), C = matrix[0].size();
    const vector<vector<int>> dirs = {{0,1},{1,0},{0,-1},{-1,0}}; // 右下左上
    vector<int> numSteps = {C, R-1};
    int r = 0, c = -1;
    int cur = 0; // 方向,4种
    vector<int> ans;
    while (numSteps[cur % 2]) {
        for (int i = 0; i < numSteps[cur % 2]; i++) {
            r += dirs[cur][0], c += dirs[cur][1];
            ans.push_back(matrix[r][c]);
        }
        numSteps[cur % 2]--;
        cur = (cur + 1) % 4;
    }
    return ans;
}
由内向外螺旋
vector<vector<int>> spiralMatrixIII(int R, int C, int r0, int c0) {
    // 往右下左上方向不断走1,1,2,2,3,3,4,4,5,5,...步
    // 从索引i(0-based)生成步数的通式是 i/2+1
    const vector<vector<int>> dirs = {{0,1}, {1,0}, {0,-1}, {-1,0}};
    vector<vector<int>> ans;
    ans.push_back({r0, c0});

    int r = r0, c = c0;
    for (int i = 0; ans.size() < R * C; i++) {
        auto &dir = dirs[i%4]; // 方向
        for (int k = 0; k < i / 2 + 1; k++) { // 走i/2+1步
            r += dir[0], c += dir[1];
            if (0 <= r && r < R && 0 <= c && c < C) ans.push_back({r, c});
        }
    }
    return ans;
}

来回遍历次对角线方向

同一次对角线上两个点r、c一增一减,r+c相等。

vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
    if (matrix.empty()) return {};
    const int R = matrix.size(), C = matrix[0].size();
    vector<vector<int>> diags(R + C - 1);
    for (int r = 0; r < R; r++) {
        for (int c = 0; c < C; c++) {
            diags[r+c].push_back(matrix[r][c]);
        }
    }
    vector<int> ans;
    for (int i = 0; i < diags.size(); i++) {
        if (i % 2 == 0) {
            ans.insert(end(ans), rbegin(diags[i]), rend(diags[i]));
        } else {
            ans.insert(end(ans), begin(diags[i]), end(diags[i]));
        }
    }
    return ans;
}

联想:同一主对角线上两点r、c同增减,r-c相等

NxN矩阵顺时针旋转90度

void rotate(vector<vector<int>>& matrix) {
    // 旋转90度跟"转置"有关
    // 顺时针旋转90度 <=等价=> 先把行倒排、再转置
    // 1 2 3      7 8 9      7 4 1 
    // 4 5 6  =>  4 5 6  =>  8 5 2
    // 7 8 9      1 2 3      9 6 3
    reverse(begin(matrix), end(matrix));
    const int N = matrix.size();
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < i; j++) {
            swap(matrix[i][j], matrix[j][i]);
        }
    }
}

如果是左转90度,那就是先先转置、再把行倒排。

01矩阵中各点到最近0值的距离

两遍扫描更新距离矩阵dist[][],第一遍从上到下从左到右、第二遍从下到上从右到左。

vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
    const int INF = 1e7;
    const int R = matrix.size(), C = matrix[0].size();
    vector<vector<int>> dist(R, vector<int>(C, INF));

    // 上=>下、左=>右
    for (int r = 0; r < R; r++) {
        for (int c = 0; c < C; c++) {
            if (matrix[r][c] != 0) {
                if (r > 0) dist[r][c] = min(dist[r][c], dist[r-1][c] + 1);
                if (c > 0) dist[r][c] = min(dist[r][c], dist[r][c-1] + 1);
            } else {
                dist[r][c] = 0;
            }
        }
    }        
    // 下=>上、右=>左
    for (int r = R - 1; r >= 0; r--) {
        for (int c = C - 1; c >= 0; c--) {
            if (matrix[r][c] != 0) {
                if (r + 1 < R) dist[r][c] = min(dist[r][c], dist[r+1][c] + 1);
                if (c + 1 < C) dist[r][c] = min(dist[r][c], dist[r][c+1] + 1);
            }
        }
    }
    return dist;
}