leetcode刷题——算法(6):搜索

搜索(2.15)

 

 

BFS

1. 计算在网格中从原点到特定点的最短路径长度

修改后做出

 

2. 组成整数的最小平方数数量(2.16)

一开始未做出

3. 最短单词路径

思考后做出

 

DFS

1. 查找最大的连通面积

思考后做出

 

2. 矩阵中的连通分量数目

可做出Ok,解法可简化

 

3. 好友关系的连通分量数目

一开始未做出

4. 填充封闭区域

一开始未做出

5. 能到达的太平洋和大西洋的区域(2.17)

一开始未做出,其实类上。

思维要灵活!

Backtracking

1. 数字键盘组合

一开始未做出

2. IP 地址划分

一开始未做出

3. 在矩阵中寻找字符串

思考后做出

 

4. 输出二叉树中所有从根到叶子的路径

思考后做出

 

5. 排列

思考后做出

 

6. 含有相同元素求排列

一开始未做出

7. 组合

修改后做出

8. 组合求和

修改后做出

 

9. 含有相同元素的组合求和

修改后做出

 

10. 1-9 数字的组合求和

思考后做出

 

11. 子集

可做出Ok,解法可优化

12. 含有相同元素求子集

可做出Ok

 

13. 分割字符串使得每个部分都是回文数

可做出Ok

 

14. 数独(2.18)

一开始未做出

15. N 皇后

思考后做出

 

BFS

在程序实现 BFS 时需要考虑以下问题:

  • 队列:用来存储每一轮遍历得到的节点;
  • 标记:对于遍历过的节点,应该将它标记,防止重复遍历。
  • 层数:如果需要层数,可以建立结构体

1. 计算在网格中从原点到特定点的最短路径长度

1091. Shortest Path in Binary Matrix(Medium)

https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/

2. 组成整数的最小平方数数量

279. Perfect Squares (Medium)

https://leetcode-cn.com/problems/perfect-squares/

1.	动态规划
class Solution {
public:
    int numSquares(int n) {
        int dp[n+1];
        for(int i=0;i<=n;i++) 
            dp[i]=i;
        for(int i=4;i<=n;i++)
            for(int j=1;i-j*j>=0;j++)
                if(dp[i-j*j]+1<dp[i]) dp[i]=dp[i-j*j]+1;
        return dp[n];
    }
};
2.	BFS
class Solution {
public:
    int numSquares(int n) {
        vector<bool> flag(n,true);
        queue<int> q;
        q.push(n);
        int step=0;
        while(!q.empty()){
            for(int i=q.size();i>0;i--){
                int cur=q.front();
                if(cur==0) return step;
                q.pop();
                for(int j=1;cur-j*j>=0;j++)
                    if(flag[cur-j*j]){
                        q.push(cur-j*j);
                        flag[cur-j*j]=false;
                    }
            }
            step++;
        }
        return -1;        
    }
};

3. 最短单词路径

127. Word Ladder (Medium)

https://leetcode-cn.com/problems/word-ladder/

DFS

在程序实现 DFS 时需要考虑以下问题:

  • 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。
  • 标记:和 BFS 一样同样需要对已经遍历过的节点进行标记。

1. 查找最大的连通面积

695. Max Area of Island (Medium)

https://leetcode-cn.com/problems/max-area-of-island/

2. 矩阵中的连通分量数目

200. Number of Islands (Medium)

https://leetcode-cn.com/problems/number-of-islands/

3. 好友关系的连通分量数目

547. Friend Circles (Medium)

https://leetcode-cn.com/problems/friend-circles/

1.	DFS
非递归解法
class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        int n=M.size(),res=0;
        bool visited[n];
        memset(visited,false,n);

        stack<int> st;
        for(int i=0;i<n;i++){
            if(visited[i]) continue;
            res++;
            visited[i]=true;
            st.push(i);
            while(!st.empty()){
                int cur=st.top();
                st.pop();
                for(int j=0;j<n;j++)
                    if(M[cur][j]==1&&!visited[j]){
                        visited[j]=true;
                        st.push(j);
                    }
            }
        }
        return res;        
    }
};
递归解法
class Solution {
public:
    void dfs(vector<vector<int>>& M,bool visited[],int i,int n){
        for(int j=0;j<n;j++)
            if(M[i][j]==1&&!visited[j]){
                visited[j]=true;
                dfs(M,visited,j,n);
            }
    }
    int findCircleNum(vector<vector<int>>& M) {
        int n=M.size(),res=0;
        bool visited[n];
        memset(visited,false,n);

        for(int i=0;i<n;i++)
            if(!visited[i]){
                res++;
                dfs(M,visited,i,n);
            } 
        return res;        
    }
};

2.	并查集
class Solution {
public:
    int findParent(int parents[],int i){
        if(parents[i]==-1) return i;
        else return findParent(parents,parents[i]);
    }
    void Union(int parents[],int a,int b){
        int fa=findParent(parents,a);
        int fb=findParent(parents,b);
        if(fa!=fb) parents[fa]=fb;
    }
    int findCircleNum(vector<vector<int>>& M) {
        int n=M.size(),res=0;
        int parents[n];
        memset(parents,-1,n*sizeof(int));
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(M[i][j]==1) Union(parents,i,j);
        for(int i=0;i<n;i++)
            if(parents[i]==-1) res++;
        return res;        
    }
};

4. 填充封闭区域

130. Surrounded Regions (Medium)

https://leetcode-cn.com/problems/surrounded-regions/

1.	DFS
class Solution {
public:
int loc[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
//非递归解法
    void dfs(vector<vector<char>>& board,int i,int j,int m,int n){
        board[i][j]='-';
        stack<pair<int,int>> st;
        st.push(make_pair(i,j));
        while(!st.empty()){
            pair<int,int> cur=st.top();
            int i=cur.first,j=cur.second;
            st.pop();
            for(int k=0;k<4;k++){
                int x=i+loc[k][0],y=j+loc[k][1];
                if(x<0||x>=m||y<0||y>=n||board[x][y]!='O') continue;
                board[x][y]='-';
                st.push(make_pair(x,y));
            }
        }
}

//递归解法
void dfs(vector<vector<char>>& board,int i,int j,int m,int n){
        board[i][j]='-';
        for(int k=0;k<4;k++){
            int x=i+loc[k][0],y=j+loc[k][1];
            if(x<0||x>=m||y<0||y>=n||board[x][y]!='O') continue;
            dfs(board,x,y,m,n);
        }
    }

    void solve(vector<vector<char>>& board) {
        if(board.size()==0) return ;
        int m=board.size(),n=board[0].size();
        for(int i=0;i<m;i++){
            if(board[i][0]=='O')
                dfs(board,i,0,m,n);
            if(board[i][n-1]=='O')
                dfs(board,i,n-1,m,n);
        }
        for(int i=0;i<n;i++){
            if(board[0][i]=='O')
                dfs(board,0,i,m,n);
            if(board[m-1][i]=='O')
                dfs(board,m-1,i,m,n);
        }
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(board[i][j]=='O')
                    board[i][j]='X';
                else if(board[i][j]=='-')
                    board[i][j]='O';
            }
    }
};

 

5. 能到达的太平洋和大西洋的区域

417. Pacific Atlantic Water Flow (Medium)

https://leetcode-cn.com/problems/pacific-atlantic-water-flow/

从边界开始遍历!

class Solution {
public:
    int loc[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
    void dfs(vector<vector<int>>& matrix,int x,int y,int m,int n,vector<vector<bool>>& canReach){
        if(canReach[x][y]) return;
        canReach[x][y]=true;
        for(int i=0;i<4;i++){
            int xx=x+loc[i][0],yy=y+loc[i][1];
            if(xx<0||xx>=m||yy<0||yy>=n||matrix[x][y]>matrix[xx][yy]) continue;
            dfs(matrix,xx,yy,m,n,canReach);
        }
    }
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& matrix) {
        vector<vector<int>> res;
        if(matrix.size()==0) return res;
        int m=matrix.size(),n=matrix[0].size();
        vector<vector<bool>> canReachP(m,vector<bool>(n,false)),canReachX(m,vector<bool>(n,false));

        for(int i=0;i<n;i++){
            dfs(matrix,0,i,m,n,canReachP);
            dfs(matrix,m-1,i,m,n,canReachX);
        }
        for(int i=0;i<m;i++){
            dfs(matrix,i,0,m,n,canReachP);
            dfs(matrix,i,n-1,m,n,canReachX);
        }
        int cnt=0;
        for(int i=0;i<m;i++)
           for(int j=0;j<n;j++){
               if(canReachP[i][j]&&canReachX[i][j])
               res.push_back((vector<int>{i,j}));
           }

        return res;
    }
};

Backtracking

Backtracking(回溯)属于 DFS。

  1. 普通 DFS 主要用在 可达性问题 ,这种问题只需要执行到特点的位置然后返回即可。
  2. 而 Backtracking 主要用于求解 排列组合 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串,这种问题在执行到特定的位置返回之后还会继续执行求解过程。

因为 Backtracking 不是立即返回,而要继续求解,因此在程序实现时,需要注意对元素的标记问题:

  1. 在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;
  2. 但是在递归返回时,需要将元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。

1. 数字键盘组合

17. Letter Combinations of a Phone Number (Medium)

https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/

class Solution {
public:
    string tel[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    void dfs(string digits,string str,vector<string>& res){
        if(str.size()==digits.size()){
            res.push_back(str);
            return;
        }
        string tmp=tel[digits[str.size()]-'0'];
        for(auto c:tmp){
            str+=c;
            dfs(digits,str,res);
            str.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        vector<string> res;
        if(digits.size()==0) return res;
        dfs(digits,"",res);
        return res;
    }
};

 2. IP 地址划分

93. Restore IP Addresses(Medium)

https://leetcode-cn.com/problems/restore-ip-addresses/

class Solution {
public:
    void dfs(string s,int n,string ip,vector<string>& res){
        if(n==4||s.empty()){
            if(s.empty()&&n==4) res.push_back(ip);
            return;
        }
        if(s[0]=='0'){
            dfs(s.substr(1),n+1,ip+s.substr(0,1)+((n!=3)?".":""),res);
            return;
        }
        int range=(s.size()<3)?s.size():3;
        for(int i=1;i<=range;i++){
            int num=stoi(s.substr(0,i));
            if(num>255||s.size()-i+1>3*(4-n)) break;
            dfs(s.substr(i),n+1,ip+s.substr(0,i)+((n!=3)?".":""),res);
        }
    }
    vector<string> restoreIpAddresses(string s) {
        vector<string> res;
        if(s.empty()) return res;
        dfs(s,0,"",res);
        return res;        
    }
};

 

3. 在矩阵中寻找字符串

79. Word Search (Medium)

https://leetcode-cn.com/problems/word-search/submissions/

4. 输出二叉树中所有从根到叶子的路径

257. Binary Tree Paths (Easy)

https://leetcode-cn.com/problems/binary-tree-paths/

5. 排列

46. Permutations (Medium)

https://leetcode-cn.com/problems/permutations/

6. 含有相同元素求排列

47. Permutations II (Medium)

https://leetcode-cn.com/problems/permutations-ii/

class Solution {
public:
    void backTracking(vector<vector<int>>& res,vector<int>& nums,vector<int> tmp,vector<bool> flag){
        if(nums.size()==tmp.size()){
            res.push_back(tmp);
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(i!=0&&nums[i]==nums[i-1]&&!flag[i-1])  //含相同元素写法
                   continue;
            if(flag[i]) continue;
            flag[i]=true;
            tmp.push_back(nums[i]);
            backTracking(res,nums,tmp,flag);
            tmp.pop_back();
            flag[i]=false;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> res;
        if(nums.size()==0) return res;
        sort(nums.begin(),nums.end());
        vector<bool> flag(nums.size(),false);
        backTracking(res,nums,vector<int>(),flag);
        return res;
    }
};

7. 组合

77. Combinations (Medium)

https://leetcode-cn.com/problems/combinations/

class Solution {
public:
    void backTracking(vector<vector<int>>& res,vector<int> tmp,int val,int n,int k){
        if(k==0){
            res.push_back(tmp);
            return;
        }
        for(int i=val;i<=n;i++){    //组合写法,i从val开始;排序从0开始
            tmp.push_back(i);       //不需要flag
            backTracking(res,tmp,i+1,n,k-1);
            tmp.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> res;
        if(k==0) return res;
        backTracking(res,vector<int>(),1,n,k);
        return res;
    }
};

8. 组合求和

39. Combination Sum (Medium)

https://leetcode-cn.com/problems/combination-sum/

9. 含有相同元素的组合求和

40. Combination Sum II (Medium)

https://leetcode-cn.com/problems/combination-sum-ii/

10. 1-9 数字的组合求和

216. Combination Sum III (Medium)

https://leetcode-cn.com/problems/combination-sum-iii/

11. 子集

78. Subsets (Medium)

https://leetcode-cn.com/problems/subsets/

class Solution {
public:
    void backTracking(vector<vector<int>>& res,vector<int>& nums,vector<int> tmp,int st,int n){
        if(tmp.size()==n){
            res.push_back(tmp);
        }
        for(int i=st;i<nums.size();i++){
            tmp.push_back(nums[i]);  //不需要flag
            backTracking(res,nums,tmp,i+1,n);
            tmp.pop_back();
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        for(int i=0;i<=nums.size();i++)
            backTracking(res,nums,vector<int>(),0,i);
        return res;
    }
};

12. 含有相同元素求子集

90. Subsets II (Medium)

https://leetcode-cn.com/problems/subsets-ii/

需要flag,解法类似9

13. 分割字符串使得每个部分都是回文数

131. Palindrome Partitioning (Medium)

https://leetcode-cn.com/problems/palindrome-partitioning/

14. 数独

37. Sudoku Solver (Hard)

https://leetcode-cn.com/problems/sudoku-solver/

从最左上角的方格开始 row = 0, col = 0。直到到达一个空方格。

  1. 从1 到 9 迭代循环数组,尝试放置数字 d 进入 (row, col) 的格子。
  2. 如果数字 d 还没有出现在当前行,列和子方块中:
  • 将 d 放入 (row, col) 格子中。
  • 记录下 d 已经出现在当前行,列和子方块中。
  • 如果这是最后一个格子row == 8, col == 8 :

意味着已经找出了数独的解。

  • 否则,放置接下来的数字。
  • 如果数独的解还没找到:

将最后的数从 (row, col) 移除。

class Solution {
public:
    bool rowUsed[9][10]={false};
    bool colUsed[9][10]={false};
    bool cubeUsed[9][10]={false};
    int cube(int row,int col){
        return (row/3)*3+col/3;
    }
    bool backTracking(vector<vector<char>>& board,int row,int col){
        while(row<9&&board[row][col]!='.'){
            row=(col==8)?row+1:row;
            col=(col==8)?0:col+1;
        }
        if(row==9) return true;
        for(int i=1;i<=9;i++){
            if(rowUsed[row][i]||colUsed[col][i]||cubeUsed[cube(row,col)][i]) 
                continue;
            board[row][col]='0'+i;
            rowUsed[row][i]=colUsed[col][i]=cubeUsed[cube(row,col)][i]=true;
            if(backTracking(board,row,col)) return true;
            rowUsed[row][i]=colUsed[col][i]=cubeUsed[cube(row,col)][i]=false;
            board[row][col]='.';
        }
        return false;
    }
    void solveSudoku(vector<vector<char>>& board) {
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++){
                if(board[i][j]=='.') continue;
                int num=board[i][j]-'0';
                rowUsed[i][num]=true;
                colUsed[j][num]=true;
                cubeUsed[cube(i,j)][num]=true;
            }
        backTracking(board,0,0);
    }
};

15. N 皇后

51. N-Queens (Hard)

https://leetcode-cn.com/problems/n-queens/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值