1. 程式人生 > 實用技巧 >2020-09-03:裸寫演算法:回形矩陣遍歷。

2020-09-03:裸寫演算法:回形矩陣遍歷。

福哥答案2020-09-03:

方法一:模擬,點陣圖方式。
跟 方法二 一樣,區別是輔助矩陣visited用點陣圖節約空間。

方法二:模擬。
可以模擬螺旋矩陣的路徑。初始位置是矩陣的左上角,初始方向是向右,當路徑超出界限或者進入之前訪問過的位置時,則順時針旋轉,進入下一個方向。
判斷路徑是否進入之前訪問過的位置需要使用一個與輸入矩陣大小相同的輔助矩陣visited,其中的每個元素表示該位置是否被訪問過。當一個元素被訪問時,將 visited 中的對應位置的元素設為已訪問。
如何判斷路徑是否結束?由於矩陣中的每個元素都被訪問一次,因此路徑的長度即為矩陣中的元素數量,當路徑的長度達到矩陣中的元素數量時即為完整路徑,將該路徑返回。

複雜度分析
時間複雜度:O(mn),其中 m 和 n 分別是輸入矩陣的行數和列數。矩陣中的每個元素都要被訪問一次。
空間複雜度:O(mn)。需要建立一個大小為 m×n 的矩陣 visited 記錄每個位置是否被訪問過。

方法三:按層模擬
可以將矩陣看成若干層,首先輸出最外層的元素,其次輸出次外層的元素,直到輸出最內層的元素。
定義矩陣的第 k 層是到最近邊界距離為 k 的所有頂點。例如,下圖矩陣最外層元素都是第 1 層,次外層元素都是第 2 層,剩下的元素都是第 3 層。
複雜度分析
時間複雜度:O(mn),其中 m 和 n 分別是輸入矩陣的行數和列數。矩陣中的每個元素都要被訪問一次。
空間複雜度:O(1)。除了輸出陣列以外,空間複雜度是常數。

程式碼用golang編寫,如下:

package test37_spiralorder

import (
    "fmt"
    "testing"
)

//https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode-solution/
//go test -v -test.run TestSpiralOrder
func TestSpiralOrder(t *testing.T) {

    const N = 3
    matrix := make([][]int, N)
    for i := 0; i < N; i++ {
        matrix[i] = make([]int, N)
        for j := 0; j < N; j++ {
            matrix[i][j] = i*N + j + 1
        }
    }
    fmt.Println(matrix)
    ret := spiralOrder1(matrix)
    fmt.Println(ret, "方法一:模擬,點陣圖")
    ret = spiralOrder2(matrix)
    fmt.Println(ret, "方法二:模擬")
    ret = spiralOrder3(matrix)
    fmt.Println(ret, "方法三:按層模擬")

}

//方法一:模擬,點陣圖
func spiralOrder1(matrix [][]int) []int {
    if len(matrix) == 0 || len(matrix[0]) == 0 {
        return []int{}
    }
    rows, columns := len(matrix), len(matrix[0])
    visited := make([]byte, (rows*columns+7)/8)

    var (
        total          = rows * columns
        order          = make([]int, total)
        row, column    = 0, 0
        directions     = [][]int{[]int{0, 1}, []int{1, 0}, []int{0, -1}, []int{-1, 0}}
        directionIndex = 0
    )

    for i := 0; i < total; i++ {
        order[i] = matrix[row][column]
        SetBitMapValue(visited, row*columns+column, true)
        nextRow, nextColumn := row+directions[directionIndex][0], column+directions[directionIndex][1]
        if nextRow < 0 ||
            nextRow >= rows ||
            nextColumn < 0 ||
            nextColumn >= columns ||
            GetBitMapValue(visited, nextRow*columns+nextColumn) {
            directionIndex = (directionIndex + 1) % 4
        }
        row += directions[directionIndex][0]
        column += directions[directionIndex][1]
    }
    return order
}

//方法二:模擬
func spiralOrder2(matrix [][]int) []int {
    if len(matrix) == 0 || len(matrix[0]) == 0 {
        return []int{}
    }
    rows, columns := len(matrix), len(matrix[0])
    visited := make([][]bool, rows)
    for i := 0; i < rows; i++ {
        visited[i] = make([]bool, columns)
    }

    var (
        total          = rows * columns
        order          = make([]int, total)
        row, column    = 0, 0
        directions     = [][]int{[]int{0, 1}, []int{1, 0}, []int{0, -1}, []int{-1, 0}}
        directionIndex = 0
    )

    for i := 0; i < total; i++ {
        order[i] = matrix[row][column]
        visited[row][column] = true
        nextRow, nextColumn := row+directions[directionIndex][0], column+directions[directionIndex][1]
        if nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn] {
            directionIndex = (directionIndex + 1) % 4
        }
        row += directions[directionIndex][0]
        column += directions[directionIndex][1]
    }
    return order
}

//方法三:按層模擬
func spiralOrder3(matrix [][]int) []int {
    if len(matrix) == 0 || len(matrix[0]) == 0 {
        return []int{}
    }
    var (
        rows, columns            = len(matrix), len(matrix[0])
        order                    = make([]int, rows*columns)
        index                    = 0
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
    )

    for left <= right && top <= bottom {
        for column := left; column <= right; column++ {
            order[index] = matrix[top][column]
            index++
        }
        for row := top + 1; row <= bottom; row++ {
            order[index] = matrix[row][right]
            index++
        }
        if left < right && top < bottom {
            for column := right - 1; column > left; column-- {
                order[index] = matrix[bottom][column]
                index++
            }
            for row := bottom; row > top; row-- {
                order[index] = matrix[row][left]
                index++
            }
        }
        left++
        right--
        top++
        bottom--
    }
    return order
}

//獲取點陣圖第index元素的值
func GetBitMapValue(data []byte, index int) bool {
    return data[index/8]&(1<<(index%8)) != 0
}

//設定點陣圖第index元素的值
func SetBitMapValue(data []byte, index int, v bool) {
    if v {
        data[index/8] |= 1 << (index % 8)
    } else {
        data[index/8] &= ^(1 << (index % 8))
    }
}

  

敲 go test -v -test.run TestSpiralOrder 命令,結果如下:


***
[評論](https://user.qzone.qq.com/3182319461/blog/1599087959)