【dfs+回溯专题】

dfs+回溯专题

Leetcode.17电话号码的字母组合
Leetcode.79单词搜索 (递归跳出条件的顺序很nb if(word[u]!=board[x][y])return false;
if(u==word.size()-1)return true;)
Leetcode.46全排列
Leetcode.47全排列 II (不会,难点:判重,想死我了,visit 代表位置是否被visit过了)
Leetcode.78子集 (上一题变题,难点:判重,visit 代表数是否被visit过了)
Leetcode.子集 II (再让我做一遍可能还不大行)
Leetcode.216组合总和 III
Leetcode.52N皇后 II (被自己厉害到了,和大佬思路一样dfs(row))
Leetcode.37解数独 (递归先正确化,再判断跳出)
Leetcode.473火柴拼正方形 (剪枝例题)

*不重复->递归函数需要start参数

一、Leetcode.17电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

  	string anniu[8]={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> letterCombinations(string digits) {
        if(digits.empty())return vector<string>();
        vector<string>ans(1,"");
        for(auto digit:digits){
            vector<string>now;
            for(int i=0;i<anniu[digit-'2'].size();i++){
                for(int j=0;j<ans.size();j++)
                now.push_back(ans[j]+anniu[digit-'2'][i]);
            }
            ans=now;
        }
        return ans;
    }

二、Leetcode.79单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

    int m,n;
    int dx[4]={-1,0,1,0};
    int dy[4]={0,1,0,-1};
    bool dfs(vector<vector<char>>& board,int x,int y,string& word,int u){
        if(board[x][y]!=word[u])return false;
        if(u==word.size()-1)return true;
        board[x][y]='.';
        for(int i=0;i<4;i++){
            int a=x+dx[i];
            int b=y+dy[i];
            if(a>=0&&a<m&&b>=0&&b<n){
                if(dfs(board,a,b,word,u+1))return true;
            }
        }
        board[x][y]=word[u];
        return false;
    }
    bool exist(vector<vector<char>>& board, string word) {
        if(board.size()==0||board[0].size()==0)return false;
        m=board.size();
        n=board[0].size();
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(dfs(board,i,j,word,0)==true)
                return true;
            }
        }
        return false;
    }

三、Leetcode.46全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

  int n;
    vector<bool>visit;
    vector<vector<int>>ans;
    vector<int>path;
    vector<vector<int>> permute(vector<int>& nums) {
        n=nums.size();
        visit=vector<bool>(n);
        dfs(nums,0);
        return ans;
    }
    void dfs(vector<int>& nums,int u){
        if(u==n){
            ans.push_back(path);
            return ;
        }
        for(int i=0;i<n;i++){
            if(visit[i]==0){
                visit[i]=1;
                path.push_back(nums[i]);
                dfs(nums,u+1);
                path.pop_back();
                visit[i]=0;
            }
        }
    }

四、Leetcode.47全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

 	int n;
    vector<vector<int>>ans;
    vector<int>path;
    vector<bool>visit;
    void dfs(vector<int>& nums,int u,int start){//第u个数
        if(u==n){
            ans.push_back(path);
            return;
        }
        for(int i=start;i<n;i++){
            if(visit[i]==false){
                visit[i]=true;
                path[i]=nums[u];
                dfs(nums,u+1,u+1<n&&nums[u+1]==nums[u]?i+1:0);
                visit[i]=false;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        n=nums.size();
        path=vector<int>(n);
        visit=vector<bool>(n);
        dfs(nums,0,0);
        return ans;
    }

五、Leetcode.78子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

  vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>>ans;
        for(int i=0;i<(1<<nums.size());i++)
        {
            vector<int>temp;
            for(int j=0;j<nums.size();j++)
            {
                if(i>>j&1)temp.push_back(nums[j]);
            }
            ans.push_back(temp);
        }
        return ans;
    }

六、Leetcode.90子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

  	vector<vector<int>>ans;
    vector<int>path;
    void dfs(vector<int>& nums,int u){
        if(u==nums.size()){
            ans.push_back(path);
            return;
        }
        int k=0;
        while(u+k<nums.size()&&nums[u+k]==nums[u]){
            k++;
        }
        for(int i=0;i<=k;i++){
            dfs(nums,u+k);
            path.push_back(nums[u]);
        }
        for(int i=0;i<=k;i++)path.pop_back();
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        dfs(nums,0);
        return ans;
    }

七、Leetcode.216组合总和 III

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

  	vector<vector<int>>ans;
    vector<int>path;
    void dfs(int k,int start,int n){
        if(k==0){
            if(n==0)ans.push_back(path);
            return;
        }
        for(int i=start;i<=9;i++){
            path.push_back(i);
            dfs(k-1,i+1,n-i);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        dfs(k,1,n);
        return ans;
    }

八、Leetcode.52N皇后 II

n 皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。

  int ans=0;
    int n;
    vector<bool>col,d,ud;
    void dfs(int level){
        if(level==n){
            ans++;
            return;
        }
        for(int i=0;i<n;i++){
            if(!col[i]&&!d[i+level]&&!ud[i-level+n]){
                col[i]=d[i+level]=ud[i-level+n]=true;
                dfs(level+1);
                col[i]=d[i+level]=ud[i-level+n]=false;
            }
        }
    }
    int totalNQueens(int _n) {
        n=_n;
        col=vector<bool>(n);
        d=ud=vector<bool>(2*n);
        dfs(0);
        return ans;
    }

九、Leetcode.37解数独

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

  bool row[9][10]={0};
    bool col[9][10]={0};
    bool cell[3][3][10]={0};
    bool dfs(vector<vector<char>>& board,int x,int y){
        if(y==9)x++,y=0;
        if(x==9)return true;
        if(board[x][y]!='.')return dfs(board,x,y+1);
        for(int i=0;i<9;i++){
            if(!row[x][i]&&!col[y][i]&&!cell[x/3][y/3][i]){
                row[x][i]=col[y][i]=cell[x/3][y/3][i]=true;
                board[x][y]='1'+i;
                if(dfs(board,x,y+1))return true;
                board[x][y]='.';
                row[x][i]=col[y][i]=cell[x/3][y/3][i]=false;
            }
        }
        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]!='.'){
                    row[i][board[i][j]-'1']=true;
                    col[j][board[i][j]-'1']=true;
                    cell[i/3][j/3][board[i][j]-'1']=true;
                }
            }
        dfs(board,0,0);
    }

十、Leetcode.473火柴拼正方形

你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。

如果你能使这个正方形,则返回 true ,否则返回 false 。

  vector<bool>visit;
    bool dfs(vector<int>& matchsticks,int u,int cur,int length){
        if(cur==length){
            u++,cur=0;
        }
        if(u==4)return true;
        for(int i=0;i<matchsticks.size();i++){
            if(!visit[i]&&matchsticks[i]+cur<=length){
                visit[i]=true;
                if(dfs(matchsticks,u,cur+matchsticks[i],length))return true;
                visit[i]=false;
                if(cur==0)return false;
                if(cur+matchsticks[i]==length)return false;
                while(i+1<matchsticks.size()&&matchsticks[i]==matchsticks[i+1])i++;
            }
        }
        return false;
    }
    bool makesquare(vector<int>& matchsticks) {
        int sum=0;
        for(int i=0;i<matchsticks.size();i++){
            sum+=matchsticks[i];
        }
        if(matchsticks.size()==0||sum%4)return false;
        visit=vector<bool>(matchsticks.size());
        sort(matchsticks.begin(),matchsticks.end());
        reverse(matchsticks.begin(),matchsticks.end());
        return dfs(matchsticks,0,0,sum/4);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值