【c/c++算法刷题笔记】—— LeetCode打卡04


【前言】DFS + 回溯 第二篇

1 全排列(去重)

题目描述

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。说明:解集不能包含重复的子集。

样例

输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

笔记
  1. 加减乘除优先级 大于 所有位运算
  2. 例:1 2 2 2 3 3
    每个数字可选次数(类似九宫格数字代表字母)
    1 : 0 1
    2 :0 1 2 3
    3 :0 1 2
    2 * 3 * 4 = 24种
    一种一种枚举,所有数字枚举完就找到一个方案
代码
class Solution {
public:
    vector<int> path;
    vector<vector<int>> ans;
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        dfs(nums,0);
        return ans;
    }
    void dfs(vector<int>& nums,int count){
        if(count == nums.size()){
            ans.push_back(path);
            return;
        }
        //计算当前数字的个数
        int k=0;
        while(count+k<nums.size() && nums[count+k] == nums[count]) k++;
        //从0枚举到k,枚举每种数字放到哪个位置
        for(int i=0;i<=k;i++){
            dfs(nums,count+k);
            path.push_back(nums[count]);
        }
        //恢复现场
        for(int i=0;i<=k;i++) path.pop_back();
    }
};

2 组合总和

题目描述

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。
解集不能包含重复的组合。

样例

输入: k = 3, n = 7
输出: [[1,2,4]]

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]

笔记

1 依次枚举每个数,到哪个位置
2 dfs参数:枚举到了第几个数字count,开始枚举的位置start,当前所有数的和n

代码
class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path;
    vector<vector<int>> combinationSum3(int k, int n) {
        dfs(k,1,n);
        return ans;
    }
    void dfs(int k,int start,int n){
        if(!k){ 	//省变量,和模板是一样的,满足条件返回
            if(!n) ans.push_back(path);
            return;
        }
       for(int i=start;i<=10-k;i++){ //剩下起码有k个数 9-i+1>=k
            path.push_back(i);
            dfs(k-1,i+1,n-i);
            path.pop_back();
        }
    }
};

3 N皇后 II

题目描述

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

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

样例

输入: 4
输出: 2
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],

["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]

笔记
  1. 每行每列都只能一个皇后,相当于 行从1—n递增,对 n 个数进行全排列,依次枚举每一行皇后的位置
    1 每一列只能有一个皇后,(全排列已满足此条件)
    2 每条斜线只能有一个皇后,
代码

class Solution {
public:
    int nn,sum=0;
    vector<int> path;
    vector<vector<int>> ans;
    vector<int> used;
    int totalNQueens(int n) {
        nn=n;
        used=vector<int>(n);
        dfs(0);
        return sum;
    }
    void dfs(int count){
        if(count==nn){
            sum++;
            return;
        }
        for(int i=0;i<nn;i++){
            if(used[i]==0){
                bool flag=true;
                //筛选满足题目要求的情况
                for(int j=0;j<count;j++){
                    if(abs(i+1-path[j])==abs(j+1-count-1)) {
                        flag=false;
                        break;
                    }
                }
                if(flag){
                    used[i]=1;
                    path.push_back(i+1);
                    dfs(count+1);
                    path.pop_back();
                    used[i]=0;
                }
            }
        }
    }
};

4 解数独

题目描述

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

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

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。

Note:

给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

样例

在这里插入图片描述
结果:
在这里插入图片描述

笔记

从前往后枚举每个空格 该填哪个数
状态: row[9][9] //i:每行 j:当前每个数字
col[9][9] //i:每列 j:当前每个数字
cell[3][3][9] //3×3 k:九宫格 共 9 个

代码

class Solution {
public:
    bool row[9][9]={0},col[9][9]={0},cell[3][3][9]={0}; //维护数组

    void solveSudoku(vector<vector<char>>& board) {
        for(int i=0;i<9;i++){  //遍历board
            for(int j=0;j<9;j++){
                char c= board[i][j];
                if(c!='.') {
                    int t=c-'1';
                    row[i][t]=col[j][t]=cell[i/3][j/3][t]=true; //更新状态
                }
            }
        }
        dfs(board,0,0);
    }
    bool dfs(vector<vector<char>>& board,int x,int y){
        if(y==9) x++,y=0;
        if(x==9) return true; //此处 x==9 和 y==0 两行不可对调,否则若行至右下角最后一个数,越界
        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]){
                board[x][y]=i+'1'; //result 结果数组维护
                row[x][i]=col[y][i]=cell[x/3][y/3][i]=true; //辅助数组 维护
                if(dfs(board,x,y+1)) return true;
                row[x][i]=col[y][i]=cell[x/3][y/3][i]=false;//辅助数组 恢复                
                board[x][y]='.'; //result 结果数组恢复

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值