小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

二維數(shù)組的花式遍歷技巧盤點(diǎn)

 520jefferson 2021-12-13

讀完本文,可以去力扣解決如下題目:

48. 旋轉(zhuǎn)圖像(中等)

54. 螺旋矩陣(中等)

59. 螺旋矩陣 II(中等)

圖片

有不少讀者說,看過很多公眾號歷史文章之后掌握了框架思維,可以解決大部分有套路框架可循的題目。

但是框架思維也不是萬能的,有一些特定技巧呢,屬于會者不難,難者不會的類型,只能通過多刷題進(jìn)行總結(jié)和積累。

那么本文我分享一些巧妙的二維數(shù)組的花式操作,你只要有個印象,以后遇到類似題目就不會懵圈了。

順/逆時針旋轉(zhuǎn)矩陣

對二維數(shù)組進(jìn)行旋轉(zhuǎn)是常見的筆試題,力扣第 48 題「旋轉(zhuǎn)圖像」就是很經(jīng)典的一道:

圖片

題目很好理解,就是讓你將一個二維矩陣順時針旋轉(zhuǎn) 90 度,難點(diǎn)在于要「原地」修改,函數(shù)簽名如下:

void rotate(int[][] matrix)

如何「原地」旋轉(zhuǎn)二維矩陣?稍想一下,感覺操作起來非常復(fù)雜,可能要設(shè)置巧妙的算法機(jī)制來「一圈一圈」旋轉(zhuǎn)矩陣:

圖片

但實(shí)際上,這道題不能走尋常路,在講巧妙解法之前,我們先看另一道谷歌曾經(jīng)考過的算法題熱熱身:

給你一個包含若干單詞和空格的字符串s,請你寫一個算法,原地反轉(zhuǎn)所有單詞的順序。

比如說,給你輸入這樣一個字符串:

s = 'hello world labuladong'

你的算法需要原地反轉(zhuǎn)這個字符串中的單詞順序:

s = 'labuladong world hello'

常規(guī)的方式是把s按空格split成若干單詞,然后reverse這些單詞的順序,最后把這些單詞join成句子。但這種方式使用了額外的空間,并不是「原地反轉(zhuǎn)」單詞。

正確的做法是,先將整個字符串s反轉(zhuǎn)

s = 'gnodalubal dlrow olleh'

然后將每個單詞分別反轉(zhuǎn)

s = 'labuladong world hello'

這樣,就實(shí)現(xiàn)了原地反轉(zhuǎn)所有單詞順序的目的。

我講這道題的目的是什么呢?

旨在說明,有時候咱們拍腦袋的常規(guī)思維,在計算機(jī)看來可能并不是最優(yōu)雅的;但是計算機(jī)覺得最優(yōu)雅的思維,對咱們來說卻不那么直觀。也許這就是算法的魅力所在吧。

回到之前說的順時針旋轉(zhuǎn)二維矩陣的問題,常規(guī)的思路就是去尋找原始坐標(biāo)和旋轉(zhuǎn)后坐標(biāo)的映射規(guī)律,但我們是否可以讓思維跳躍跳躍,嘗試把矩陣進(jìn)行反轉(zhuǎn)、鏡像對稱等操作,可能會出現(xiàn)新的突破口。

我們可以先將n x n矩陣matrix按照左上到右下的對角線進(jìn)行鏡像對稱

圖片

然后再對矩陣的每一行進(jìn)行反轉(zhuǎn)

圖片

發(fā)現(xiàn)結(jié)果就是matrix順時針旋轉(zhuǎn) 90 度的結(jié)果

圖片

將上述思路翻譯成代碼,即可解決本題:

// 將二維矩陣原地順時針旋轉(zhuǎn) 90 度
public void rotate(int[][] matrix) {
    int n = matrix.length;
    // 先沿對角線鏡像對稱二維矩陣
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            // swap(matrix[i][j], matrix[j][i]);
            int temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
        }
    }
    // 然后反轉(zhuǎn)二維矩陣的每一行
    for (int[] row : matrix) {
        reverse(row);
    }
}

// 反轉(zhuǎn)一維數(shù)組
void reverse(int[] arr) {
    int i = 0, j = arr.length - 1;
    while (j > i) {
        // swap(arr[i], arr[j]);
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i++;
        j--;
    }
}

肯定有讀者會問,如果沒有做過這道題,怎么可能想到這種思路呢?

其實(shí)我覺得這個思路還是挺容易想出來的,如果學(xué)過線性代數(shù),這道算法題的思路本質(zhì)就是矩陣變換,肯定可以想出來。

即便沒學(xué)過線性代數(shù),旋轉(zhuǎn)二維矩陣的難點(diǎn)在于將「行」變成「列」,將「列」變成「行」,而只有按照對角線的對稱操作是可以輕松完成這一點(diǎn)的,對稱操作之后就很容易發(fā)現(xiàn)規(guī)律了。

既然說道這里,我們可以發(fā)散一下,如何將矩陣逆時針旋轉(zhuǎn) 90 度呢

思路是類似的,只要通過另一條對角線鏡像對稱矩陣,然后再反轉(zhuǎn)每一行,就得到了逆時針旋轉(zhuǎn)矩陣的結(jié)果:

圖片

翻譯成代碼如下:

// 將二維矩陣原地逆時針旋轉(zhuǎn) 90 度
void rotate2(int[][] matrix) {
    int n = matrix.length;
    // 沿左下到右上的對角線鏡像對稱二維矩陣
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n - i; j++) {
            // swap(matrix[i][j], matrix[n-j-1][n-i-1])
            int temp = matrix[i][j];
            matrix[i][j] = matrix[n - j - 1][n - i - 1];
            matrix[n - j - 1][n - i - 1] = temp;
        }
    }
    // 然后反轉(zhuǎn)二維矩陣的每一行
    for (int[] row : matrix) {
        reverse(row);
    }
}

void reverse(int[] arr) { /* 見上文 */}

至此,旋轉(zhuǎn)矩陣的問題就解決了。

矩陣的螺旋遍歷

我的公眾號 動態(tài)規(guī)劃系列文章 經(jīng)常需要遍歷二維dp數(shù)組,但難點(diǎn)在于狀態(tài)轉(zhuǎn)移方程而不是數(shù)組的遍歷,頂多就是倒序遍歷。

今天我們講一下力扣第 54 題「螺旋矩陣」,看一看二維矩陣可以如何花式遍歷:

圖片

函數(shù)簽名如下:

List<Integer> spiralOrder(int[][] matrix)

解題的核心思路是按照右、下、左、上的順序遍歷數(shù)組,并使用四個變量圈定未遍歷元素的邊界

圖片

隨著螺旋遍歷,相應(yīng)的邊界會收縮,直到螺旋遍歷完整個數(shù)組:

圖片

只要有了這個思路,翻譯出代碼就很容易了:

List<Integer> spiralOrder(int[][] matrix) {
    int m = matrix.length, n = matrix[0].length;
    int upper_bound = 0, lower_bound = m - 1;
    int left_bound = 0, right_bound = n - 1;
    List<Integer> res = new LinkedList<>();
    // res.size() == m * n 則遍歷完整個數(shù)組
    while (res.size() < m * n) {
        if (upper_bound <= lower_bound) {
            // 在頂部從左向右遍歷
            for (int j = left_bound; j <= right_bound; j++) {
                res.add(matrix[upper_bound][j]);
            }
            // 上邊界下移
            upper_bound++;
        }

        if (left_bound <= right_bound) {
            // 在右側(cè)從上向下遍歷
            for (int i = upper_bound; i <= lower_bound; i++) {
                res.add(matrix[i][right_bound]);
            }
            // 右邊界左移
            right_bound--;
        }

        if (upper_bound <= lower_bound) {
            // 在底部從右向左遍歷
            for (int j = right_bound; j >= left_bound; j--) {
                res.add(matrix[lower_bound][j]);
            }
            // 下邊界上移
            lower_bound--;
        }

        if (left_bound <= right_bound) {
            // 在左側(cè)從下向上遍歷
            for (int i = lower_bound; i >= upper_bound; i--) {
                res.add(matrix[i][left_bound]);
            }
            // 左邊界右移
            left_bound++;
        }
    }
    return res;
}

力扣第 59 題「螺旋矩陣 II」也是類似的題目,只不過是反過來,讓你按照螺旋的順序生成矩陣:

圖片

函數(shù)簽名如下:

int[][] generateMatrix(int n)

有了上面的鋪墊,稍微改一下代碼即可完成這道題:

int[][] generateMatrix(int n) {
    int[][] matrix = new int[n][n];
    int upper_bound = 0, lower_bound = n - 1;
    int left_bound = 0, right_bound = n - 1;
    // 需要填入矩陣的數(shù)字
    int num = 1;

    while (num <= n * n) {
        if (upper_bound <= lower_bound) {
            // 在頂部從左向右遍歷
            for (int j = left_bound; j <= right_bound; j++) {
                matrix[upper_bound][j] = num++;
            }
            // 上邊界下移
            upper_bound++;
        }

        if (left_bound <= right_bound) {
            // 在右側(cè)從上向下遍歷
            for (int i = upper_bound; i <= lower_bound; i++) {
                matrix[i][right_bound] = num++;
            }
            // 右邊界左移
            right_bound--;
        }

        if (upper_bound <= lower_bound) {
            // 在底部從右向左遍歷
            for (int j = right_bound; j >= left_bound; j--) {
                matrix[lower_bound][j] = num++;
            }
            // 下邊界上移
            lower_bound--;
        }

        if (left_bound <= right_bound) {
            // 在左側(cè)從下向上遍歷
            for (int i = lower_bound; i >= upper_bound; i--) {
                matrix[i][left_bound] = num++;
            }
            // 左邊界右移
            left_bound++;
        }
    }
    return matrix;
}

至此,兩道螺旋矩陣的題目也解決了。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多