[Leetcode] 130, 131, 62

本文探讨了围堵'O'区域与回文字符串分区两种算法问题。通过广度优先搜索解决围堵问题,确保边界'O'不被翻转;采用深搜与动态规划解决回文分区问题,实现字符串的有效分割。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

130. Surrounded Regions

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.

A region is captured by flipping all 'O's into 'X's in that surrounded region.

For example,

X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

Solution: 广度优先搜索(BFS),最外面一圈的O是一定保留的,然后跟它们相连的O也能被保留下来。

Code:

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        if(board.size()==0 || board[0].size()==0) return;
        queue<pair<int, int>> q;
        //unordered_map<int, bool> visited; 这样做标记太浪费空间了,直接记录在board里面
        //第一行
        for(int i=0; i<board[0].size(); i++){
            if(board[0][i] == 'O'){
                q.push(make_pair(0, i));
                board[0][i] = '+';//即能标记又能去重
            } 
            if(board.back()[i] == 'O'){
                q.push(make_pair(board.size()-1, i));
                board[board.size()-1][i] = '+';
            }
        }
        for(int i=0; i<board.size(); i++){
            if(board[i][0] == 'O'){
                q.push(make_pair(i, 0));
                board[i][0] = '+';
            }
            if(board[i].back() == 'O'){
                q.push(make_pair(i, board[0].size()-1));
                board[i][board[0].size()-1] = '+';
            }
        }
        
        while(!q.empty()){
            int x = q.front().first;
            int y = q.front().second;
            if(x>0 && board[x-1][y]=='O'){
                q.push(make_pair(x-1,y));
                board[x-1][y] = '+';
            }
            if(y>0 && board[x][y-1]=='O'){
                q.push(make_pair(x,y-1));
                board[x][y-1] = '+';
            }
            if(x<board.size()-1 && board[x+1][y]=='O'){
                q.push(make_pair(x+1,y));
                board[x+1][y] = '+';
            }
            if(y<board[0].size()-1 && board[x][y+1]=='O'){
                q.push(make_pair(x,y+1));
                board[x][y+1] = '+';
            }
            q.pop();
        }
        
        for(int i=0; i<board.size(); i++){
            for(int t=0; t<board[i].size(); t++){
                if(board[i][t]=='O')
                    board[i][t]='X';
                else if(board[i][t]=='+')
                    board[i][t]='O';
            }
        }
    }
};



131. Palindrome Partitioning

Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

For example, given s = "aab",
Return

[
  ["aa","b"],
  ["a","a","b"]
]

Solution(1):深搜,每一步都将string分成两部分,一部分为一定包第一个字母的字符串,对剩下的字母构成的字符串继续递归,时间复杂度O(n^2),空间复杂度O(n)

Code:

class Solution {
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>> ans;
        vector<string> path; 
        dfs(0, s.size(), s, path, ans);
        return ans;
    }
private:
    bool isPalindrome(string& s){
        for(int i=0, j=s.size()-1; i<j; i++,j--){
            if(s[i]!=s[j]) return false;
        }
        return true;
    }
    void dfs(int first, int end, string& s, vector<string>& path, vector<vector<string>>& ans){
        if(first == end){
            ans.push_back(path);
            return;
        }
        for(int i=1; i<=end-first; i++){
            string sub = s.substr(first, i);
            if(isPalindrome(sub)){
                path.push_back(sub);
                dfs(first+i, end, s, path, ans);
                path.pop_back();
            }
        }
    }
};

Solution(2): 动态规划。

Code:

class Solution {
public:
    vector<vector<string>> partition(string s) {
        int n = s.size();
        if(n==0){
            vector<vector<string>> ans;
            ans.push_back(vector<string>());
            return ans;
        }
        //预处理,也是动规思想
        bool Palindrome[n][n];//Palindrome[x][y],x-y之间的子串是否为回文
        fill_n(&Palindrome[0][0], n*n, false);//Palindrome[x][y]要求x<=y,因此实际上真正有用的空间只有一半
        for(int i=0; i<n; i++){
            for(int t=i; t>=0; t--)
                if(t<i-2 && i>0)
                    Palindrome[t][i] = s[i]==s[t] && Palindrome[t+1][i-1];
                else
                    Palindrome[t][i] = s[i]==s[t];
        }
        //动规
        vector<vector<string>> partition[n];//记录前n个字符partition的解集
        for(int i=0; i<n; i++){//加入一个新字符
            for(int t=i; t>0; t--){//遍历新字符作为最后一个能构成的所有子串
                string sub = s.substr(t,i-t+1);
                if(isPalindrome(sub)){
                    //如果子串是回文,则将不包含子串在内的前t个字符的解集逐一加上这个回文加入当前寻找的解集
                    for(vector<string> v:partition[t-1]){
                        v.push_back(sub);
                        partition[i].push_back(v);
                    }
                }
            }
            //t=0的情况
            string sub = s.substr(0,i+1);
            if(isPalindrome(sub)) partition[i].push_back(vector<string>{sub});
        }
        return partition[n-1];
    }
private:
    bool isPalindrome(string& s){
        for(int i=0, j=s.size()-1; i<j; i++,j--){
            if(s[i]!=s[j]) return false;
        }
        return true;
    }
};


62. Unique Paths

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?


Above is a 3 x 7 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

Solution(1): 深搜,直接深搜会超时,使用数组记录已经算过的值(备忘录法)。

Code:

class Solution {
public:
    int uniquePaths(int m, int n) {
        //this->f = vector<vector<int> >(m + 1, vector<int>(n + 1, 0)); 
        //会报runtime erro,free()的时候无法成功,为什么?
        for(int i=0; i<=m; i++){
            up.push_back(vector<int>());
            for(int t=0; t<=n; t++){
                up.back().push_back(0);
            }
        }
        return dfs(m, n);
    }
private:
    vector<vector<int>> up;
    int dfs(int m, int n) {
        if(m<=0 || n<=0) return 0;
        if(m==1 || n==1) return 1;
        if(up[m-1][n]==0) up[m-1][n] = dfs(m-1, n);
        if(up[m][n-1]==0) up[m][n-1] = dfs(m, n-1);
        return up[m-1][n]+up[m][n-1];
    }
};

Solution(2): 动规,设状态为up[i][j],表示从起点(1; 1) 到达(i; j) 的路线条数,则状态转移方程为:up[i][j]=up[i-1][j]+up[i][j-1]

Code:

class Solution {
public:
    int uniquePaths(int m, int n) {
        int up[m][n];
        for(int i=0; i<n; i++) up[m-1][i] = 1;
        for(int i=0; i<m; i++) up[i][n-1] = 1;
        for(int i=m-2; i>=0; i--){
            for(int t=n-2; t>=0; t--){
                up[i][t] = up[i+1][t]+up[i][t+1];
            }
        }
        return up[0][0];
    }
};

Solution(3): 数学方法,机器人一共需要走m+n-2步,其中有m-1步是向下走,问一共有多少种走法,即m+n-2步中选择m-1步向下一共有多少种组合方式,即C(m+n-2,m-1)。

Code:

class Solution {
public:
    int uniquePaths(int m, int n) {
        //C(m+n-2,m-1)
        int k = min(m,n);//防止溢出
        long long ans = 1;//防止溢出
        for(int i=0,j=m+n-2; i<k-1; i++,j--)
            ans *= j;
        for(int i=1; i<=k-1; i++)
            ans /= i;
        return ans;
    }
};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值