递归回溯整理(leetcode)

1 求子集  78

题目:给定nums求所有子集(数组中不含重复元素),以[1,2,3]为例, 8个子集

思路:每个数字都有选和不选两种情况

一步步考虑

先考虑生成[1], [1,2] , [1, 2, 3] 的代码

vector<int> nums = {1, 2, 3};
vector<int> item;
vector<vector<int>> ret;
void generate(vector<int> &item, vector<vector<int>> &ret){
    for(int i=0;i<nums.size();i++){
        item.push_back(nums[i])
        ret.push_back(nums);
    }
}

这里注意python 有所不同

nums = [1, 2, 3]
ret = []
item = []
def generate(nums, ret, item):
    for i in range(len(nums)):
        item.append(nums[i])
        ret.append(item.copy()) #之里必须用copy  否则就存成[[1,2,3],[1,2,3],[1,2,3]]
  

第二步 考虑用递归生成

vector<int> nums = {1, 2, 3};
vector<int> item;
vector<vector<int>> ret;
void generate(int i, vector<int> &item, vector<vector<int>> &ret){
    if(i>nums.size(){
        return
    }
    item.push_back(nums[i])
    ret.push_back(nums);
    generate(i+1, item, ret);
}

然后思考题目

例如 [1,2,3,4,5]  对于第一个元素 我们考虑 两种情况 放入1 和 不放入1,  之后再处理[2, 3, 4, 5]

 

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> item;
        vector<vector<int>> result;
        result.push_back(item);
        generate(0, nums, result, item);
        return result;
    }
private:
    void generate(int i, vector<int> &nums, vector<vector<int>> &result, vector<int> &item){
        if(i >= nums.size()){
            return;
        }else{
            item.push_back(nums[i]);
            result.push_back(item);
            generate(i+1, nums, result, item);
            item.pop_back();
            generate(i+1, nums, result, item);
            
        }
    }
};

nums = [1, 2, 3]    result = [ [ ], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3] ]

 

2 子集2 90

题目:数组中可能包含重复元素 [2, 1, 2, 2] , 得到[1, 2, 2] 和 [2, 1, 2] 属于一样的

如果光对结果进行去重的话,是无法去重这样的,  可以先对nums进行排序,就不会出现这种情况

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int>> result;
        int num = 1 << nums.size();
        sort(nums.begin(), nums.end());
        for(int i = 0;i<num;i++){
            vector<int> item;
            for(int j = 0;j<nums.size();j++){
                if(i & 1 << j){
                    item.push_back(nums[j]);
                }
            }
            if(find(result.begin(),result.end(),item) == result.end()){
                result.push_back(item);
            }
        }
        return result;
    }
};

3 组合数之和2 40 

题目: 求这组数所有子集中和为target的的子集

思路:还是应用之前的方法求子集,多存一个cur_sum 如果cur_sum>target 进行剪枝

python版本 看着方便

class Solution:
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        ret = []
        item = []
        cur_sum = 0
        candidates.sort()
        self.generate(0, candidates, target, cur_sum, ret, item)
        return ret
    def generate(self, i, candidates, target, cur_sum, ret, item):
        if cur_sum > target or i >= len(candidates):
            return;
        item.append(candidates[i])
        cur_sum += candidates[i]
        if cur_sum == target and item not in ret:
            ret.append(item.copy())
        self.generate(i+1, candidates, target, cur_sum, ret, item)
        item.pop()
        cur_sum  -= candidates[i]
        self.generate(i+1, candidates, target, cur_sum, ret, item)

4 生成括号 22

题目:生成n组括号所有的合法组合

例如 n=3   结果为  ["((()))", "(()())", "(())()", "()(())", "()()()"]

思路:

先考虑生成所有括号,然后对不合法的进行剪枝。 产生子集 对于每个元素时考虑 选与不选两种情况, 对于这道题 对于每个元素是 考虑 是左括号 还是右括号,必定有一个。

生成所有括号代码(python)

def generate(i, n, result, item):
    if i>=n:
        result.append(item)
        return
    item += '('
    
    generate(i+1, n, result, item)
    item = item[:-1]
    item += ')'   #回溯的思想
    generate(i+1, n ,result, item)
ret = []
item = ''
generate(0, 6, ret, item)

生成了64 个字符串,2**6个

代码可以简化成

def generate(i, n, result, item):
    if i>=n:
        result.append(item)
        return
    generate(i+1, n, result, item+'(')
    generate(i+1, n ,result, item+')')

考虑什么样的放置是不符合的 , 分两方面 1 放左括号:考虑不超过n个, 右括号:不能先与左括号放置,增加两个变量left,right表示还可以放置的左括号数量和右括号数量

class Solution:
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        result = []
        item = ''
        self.generate(0, n*2, result, item, n, n)
        return result;
    
    def generate(self, i, n, result, item, left, right):
        if i>=n:
            result.append(item)
            return
        if left> 0:
            self.generate(i+1, n, result, item+'(', left-1, right)
        if right > left:
            self.generate(i+1, n ,result, item+')', left, right-1)

5 N皇后 51

题目:将N个皇后摆放在N*N的棋盘上,有多少种摆放方式

思路:用一个mark数组标记不能摆放的位置,一个一个尝试

 

 先考虑  mark数组的更新代码

def put_down_queen(x, y, mark):
    dx = [-1, 1, 0, 0, -1, 1, -1, 1]  #构建方向向量
    dy = [0, 0, 1, -1, -1, 1, 1, -1]
    mark[x][y] = 1
    for i in range(1, len(mark)):
        for j in range(8):
            new_x = x + i*dx[j]
            new_y = y + i*dy[j]
            if(new_x>= 0 and new_x < len(mark) and new_y>=0 and new_y < len(mark)):
                mark[new_x][new_y] = 1

 最终实现代码

from copy import deepcopy
class Solution:
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        
        location = [['.' for _ in range(n)] for _ in range(n)]
        mark = [[0 for _ in range(n)] for _ in range(n)]
        ret = []
        self.generate(0, n, mark, ret, location)
        c = []
        for i in ret:
            c.append([''.join(x) for x in i])
        return c
    def generate(self, k, n, mark, ret, location):
        if k == n:
            ret.append(deepcopy(location))
        else:
            for i in range(n):
                if mark[k][i] == 0:
                    temp_mark = deepcopy(mark)
                    location[k][i] = 'Q'
                    self.put_down_queen(k, i, mark)
                    self.generate(k+1, n, mark, ret, location)
                    mark = temp_mark
                    location[k][i] = '.'
    def put_down_queen(self, x, y, mark):
        dx = [-1, 1, 0, 0, -1, 1, -1, 1]  #构建方向向量
        dy = [0, 0, 1, -1, -1, 1, 1, -1]
        mark[x][y] = 1
        for i in range(1, len(mark)):
            for j in range(8):
                new_x = x + i*dx[j]
                new_y = y + i*dy[j]
                if(new_x>= 0 and new_x < len(mark) and new_y>=0 and new_y < len(mark)):
                    mark[new_x][new_y] = 1

这里注意一个坑, 开始直接用的list.copy  一直不对,后来改成deepcopy 才可以, list.copy值对第一层是深拷贝,对于嵌套的list是浅拷贝,因为嵌套list中存放的是地址  

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值