二維矩陣——從LeetCode題海中總結常見套路

二維矩陣的有套路嗎?當然有,但是不如回溯、貪心這類題有模板,但是很多題的思路可以舉一反三的

目錄

先遍歷記錄在清零的福利題:LeetCode.73矩陣置零&&面試題01.08.零矩陣

二維矩陣中的經典:LeetCode54.螺旋矩陣

劍指offer經典:LeetCode74.搜索二維矩陣

類似上一題的:LeetCode240.搜索二維矩陣II

二維二分法:LeetCode378.有序矩陣中第K小的元素

LeetCode.面試01.07.旋轉矩陣


先遍歷記錄在清零的福利題:LeetCode.73矩陣置零&&面試題01.08.零矩陣

思路有很多種,但是最後的複雜度都一樣O(M+N)

這裏使用的是先記錄要清零的行數和列數,再遍歷一遍進行清零

當然,拿到這題首先的思路是:呵呵,邊遍歷邊清零不行麼?當然不行,這樣會影響下一個判斷!

高讚的思路:

空間複雜度 O(2) ,用兩個布爾變量就可以解決。方法就是利用數組的首行和首列來記錄 0 值。從數組下標的 A[1][1] 開始遍歷,兩個布爾值記錄首行首列是否需要置0。

這種思路和上面的大同小異,只是充分利用的矩陣的首行和首列,降低了空間複雜度

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        // 開闢兩個一維數組存放要清零的行和列
        bool col[matrix.size()];
        bool row[matrix[0].size()];
        // 初始化
        for(int i = 0; i<matrix.size(); i++)
            col[i] = false;
        for(int j = 0; j<matrix[0].size(); j++)
            row[j] = false;
        // 遍歷記錄
        for(int i = 0; i<matrix.size(); i++) {
            for(int j = 0; j<matrix[0].size(); j++) {
                if(matrix[i][j] == 0) {
                    col[i] = true;
                    row[j] = true;
                }
            }
        }
        // 將這一行清零
        for(int i = 0; i<matrix.size(); i++) {
            if(col[i]) {
                for(int j = 0; j<matrix[0].size(); j++) {
                    matrix[i][j] = 0;
                }
            }
        }
        // 將這一列清零
        for(int j = 0; j<matrix[0].size(); j++) {
            if(row[j]){
                for(int i = 0; i<matrix.size(); i++) {
                    matrix[i][j] = 0;
                }
            }
        }
        return;
    }
};
class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        // 開兩個數組分別記錄需要置零的行和列
        bool col[matrix.size()];
        bool row[matrix[0].size()];
        // 先初始化數組
        for(int i = 0; i<matrix.size(); i++)
            col[i] = false;
        for(int i = 0; i<matrix[0].size(); i++)
            row[i] = false;
        // 遍歷一般進行查找需要置零的行和列
        for(int i = 0; i<matrix.size(); i++) 
            for(int j = 0; j<matrix[0].size(); j++) 
                if(matrix[i][j] == 0) {
                    col[i] = true;
                    row[j] = true;
                }
        // 分別遍歷行和列進行判斷與置零
        for(int i = 0; i<matrix.size(); i++) 
            if(col[i]) 
                for(int j = 0; j<matrix[0].size(); j++) 
                    matrix[i][j] = 0;
        for(int j = 0; j<matrix[0].size(); j++) 
            if(row[j]) 
                for(int i = 0; i<matrix.size(); i++) 
                    matrix[i][j] = 0;
    }
};

二維矩陣中的經典:LeetCode54.螺旋矩陣

這道題的思路很清晰,但是一次AC難度可不小,可以當做一個經典模板題來處理!

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> ans;
        if(matrix.empty()||matrix[0].empty())
            return ans;
        int up = 0, down = matrix.size()-1, left = 0, right = matrix[0].size()-1;
        while (true) {
            for(int i = left; i<=right; i++)
                ans.push_back(matrix[up][i]);
            if(++up>down)
                break;
            for(int i = up; i<=down; i++)
                ans.push_back(matrix[i][right]);
            if(--right<left)
                break;
            for(int i = right; i>=left; i--)
                ans.push_back(matrix[down][i]);
            if(--down<up)
                break;
            for(int i = down; i>=up; i--)
                ans.push_back(matrix[i][left]);
            if(++left>right)
                break;
        }
        return ans;
    }
};

劍指offer經典:LeetCode74.搜索二維矩陣

思路就是利用升序矩陣的性質,從右上角開始搜索,總的複雜度O(M+N),還是比較理想的

這道題刷過劍指offer應該印象深刻吧!

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.size()==0)
            return false;
        int i = 0; 
        int j = matrix[0].size()-1;
        while (i<matrix.size()&&j>=0) {
            if ( matrix[i][j]>target ) {
                j--;
            }else if (matrix[i][j]<target) {
                i++;
            }else {
                return true;
            }
        }
        return false;
    }
};

類似上一題的:LeetCode240.搜索二維矩陣II

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.size()==0)
            return false;
        // 使用雙指針從右上角進行查找
        int i = 0;
        int j = matrix[0].size()-1;
        while (i<matrix.size()&&j>=0) {
            if(matrix[i][j]>target) {
                j--;
            }else if(matrix[i][j]<target) {
                i++;
            }else{
                return true;
            }
        }
        return false;
    }
};

二維二分法:LeetCode378.有序矩陣中第K小的元素

這個二分比較難,思路上比較難

二分的基準是以整個矩陣中的mid,以這個mid統計矩陣有多少個數大於mid,多少個數小於mid

當然,在尋找mid的過程也要利用排序矩陣的性質

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int row = matrix.size();
        int col = matrix[0].size();
        int left = matrix[0][0];
        int right = matrix[row-1][col-1];
        while (left<right) {
            // 每次循環都保證第K小的數在start~end之間,當start==end,第k小的數就是start
            int mid = (left+right)/2;
            // 找二維矩陣中<=mid的元素總個數
            int count = findSmallThanMid(matrix, mid, row, col);
            if (count < k) {
                // 第k小的數在右半部分,且不包含mid
                left = mid+1;
            }else {
                // 第k小的數在左半部分,可能包含mid
                right = mid;
            }
        }
        return right;
    }
private:
    // 以列爲單位找,找到每一列最後一個<=mid的數即知道每一列有多少個數<=mid
    int findSmallThanMid(vector<vector<int>> & matrix, int mid, int row, int col) {
        int i = row-1;
        int j = 0;
        int count = 0;
        while (i>=0 && j < col) {
            if (matrix[i][j] <= mid) {
                count += i+1;
                j++;
            }else {
                i--;
            }
        }
        return count;
    }
};

LeetCode.面試01.07.旋轉矩陣

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        if(matrix.size()==0||matrix.size()!=matrix[0].size())
            return;
        int n = matrix.size();
        for(int layer = 0;layer<n/2;layer++){
            int first = layer;
            int last = n-1-layer;
            for(int i=first;i<last;i++){
                int offset = i-first;
                int top = matrix[first][i];//存儲上邊
                //左邊移動到上邊
                matrix[first][i] = matrix[last-offset][first];
                //下邊移動到左邊
                matrix[last-offset][first] = matrix[last][last-offset];
                //右邊移動到下邊
                matrix[last][last-offset] = matrix[i][last];
                //上邊移動到右邊
                matrix[i][last] = top;
            }
        }
        return;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章