代码随想录二刷|回溯4

数组有重复的元素,对组合去重:

(1)原数组可以排序:排序,相同的元素都挨着。如果前一个的used是false并且和这一个相同,就跳过

(2)原数组不可以排序:对于每一个节点,它下一步选取的元素不可以重复

从start开始遍历:for循环表示填充这一层,从start开始为父节点找儿子(start作为组合下一个元素做为儿子/start+1作为组合下一个元素做儿子/…)

非递减子序列

题干

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

思路

(1)去重:

1)不能排序

2)对于每一层不能重复使用同样的元素(同一个父亲不能多次选择同样的儿子)

3)在for前面创建集合

每次遇到num[i],如果集合里有,那么就跳过

没有,则加入集合,加入答案,递归,从答案中拿走

集合元素在回溯的时候不要拿出来

4)更高效的方法:用数组映射,因为num元素的范围是[-100.100]

元素+100作为下标,用值表示是否用到

class Solution {
public:
    vector<vector<int>> res;
    vector<int> ans;
    void f(vector<int>& nums, int start) {
        if (ans.size() >= 2) {
            res.push_back(ans);
        }
        unordered_set<int> used;
        for (int i = start; i < nums.size(); i++) {
            if (used.find(nums[i]) != used.end())
                continue;
            if (ans.size() != 0 && ans[ans.size() - 1] > nums[i])
                continue;
            ans.push_back(nums[i]);
            used.insert(nums[i]);
            f(nums, i + 1);
            ans.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        f(nums, 0);
        return res;
    }
};

(2)存答案:条件是ans里面有两个以上的元素,存后不返回

(3)终止条件是start大于等于num.size(),for自然实现

排列问题

全排列

题干

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

思路

(1)排列问题不用start表示每一层遍历的起点

(2)每次都从头到尾遍历num,如果已经用过就跳过

used标记—加答案—递归—清除答案–清除标记

class Solution {
public:
    vector<vector<int>>res;
    vector<int>ans;
    void f(vector<int>&nums,vector<bool>& used){
        if(ans.size()==nums.size()){
            res.push_back(ans);
            return;
        }
        for(int i=0;i<nums.size();i++){
            if(used[i])continue;
            used[i]=true;
            ans.push_back(nums[i]);
            f(nums,used);
            ans.pop_back();
            used[i]=false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool>used(nums.size(),false);
        f(nums,used);
        return res;
    }
};

棋盘搜索问题

n皇后:

题干

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

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

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

思路

(其实判断终止的方式和引入的参数是由我们用树表示搜索过程的方式决定的)

(1)参数

1)n

2)行号row

3)答案board

(答案之所以不能用全局变量,是因为答案初始化需要n,只有传入n才能定义)

(2)终止条件:row为n,遍历完所有行,此时收集答案

(为什么每行确定一个元素是皇后就可以向下一行移动:每行之可以有一个皇后)

(3)单次递归:遍历列

如果元素有效:放皇后,递归,把格子变回空的

(4)是否有效:(封装成函数)

1)同行是否有皇后

2)同列是否有皇后

3)右上是否有皇后(row小,col大)

4)左上是否有皇后(row小,col小)

class Solution {
public:
    vector<vector<string>>res;
    bool is_valid(int row,int col,vector<string>& board,int n){
        for(int i=0;i<row;i++){
            if(board[i][col]=='Q')return false;
        }
        for(int i=0;i<col;i++){
            if(board[row][i]=='Q')return false;
        }
        for(int i=1;i<=col&&i<=row;i++){
            if(board[row-i][col-i]=='Q')return false;
        }
        for(int i=1;i+col<n&&i<=row;i++){
            if(board[row-i][col+i]=='Q')return false;
        }
        return true;
    }
    void f(int row,vector<string>& board,int n){
        if(row==n){
            res.push_back(board);
            return;
        }
        for(int i=0;i<n;i++){
            if(is_valid(row,i,board,n)){
                board[row][i]='Q';
                f(row+1,board,n);
                board[row][i]='.';
            }
        }
    }
    vector<vector<string>> solveNQueens(int n) {
        vector<string>board(n,string(n,'.'));
        f(0,board,n);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值