LeetCode刷题---递归回溯分治【2020第一版】

# 诗经·秦风·无衣
岂曰无衣,与子同袍。王于兴师,修我戈矛。与子同仇。
岂曰无衣,与子同泽。王于兴师,修我矛戟。与子谐作。
岂曰无衣,与子同裳。王于兴师,修我甲兵。与子谐行。
#把正确的时间拿来看看书而不是低级趣味。。。

0.摘要

\qquad 递归的原则:当前步骤处理当前的问题,递归处理后续问题;
\qquad 回溯:探索到某一步时,发现原先选择达不到目标,则后退一步重新选择,走不通就退回再走
\qquad 分治:将原问题分解为若干个**“不相关”**的子问题。

1.回溯法

1.1 基于暴力的二分树

在这里插入图片描述
在这里插入图片描述

#include<vector>
vector<vector<int>> subsets(vector<int>& nums)
{
	vector<vector<int>> result;
	vector<int> item;
	result.push_back(item); //先将空集入v
	generate(0,nums,item,result);
	return result;
}
void generate(int i, vector<int>& item, vector<vector<int>>& reuslt)
{
	if(i==nums.size()) return;
	item.push_back(nums[i]);
	result.push_back(item); //选择第i个元素,并写入结果
	generate(i+1,nums,item,result); //递归后续元素
	item.pop_back(); //不选择第i个元素
	generate(i+1,nums,item,result); //递归后续元素	
}

利用二进制数模拟三个元素【A,B,C】左右位置表示进制

vector<vector<int>> subsets(vector<int>&nums)
{
	vector<vector<int>> result;
	int iterations = 1<<nums.size(); //匹配总可能数
	for(int i=0; i<iterations; ++i)
	{
		vector<int> item;
		//将每一个位置的j赋予底幂,匹配是否在item中
		for(int j=0; j<nums.size(); ++j)
		{
			if(i&&(1<<j))
			{
				item.push_back(nums[j]);
			}
			result.push_back(item);
		}
	}
	return result;
}

1.2递归树剪枝,降低复杂度

在这里插入图片描述
A:对于明显不满足要求的结果,提前终止递归

#include<vector>
#include<set>
#include<algorithm>
 vector<vector<int>> combinationSum2(vector<int>& candidates, int target) 
 {
 	sort(candiates.begin(),candidates.end());
 	vector<int> item;
 	vector<vector<int>> result;
 	set<vector<int>> res_set;
 	generate(0,candidates,item,result,res_set,0,target); 	
 	return result;
 }
 void generate(int i, vector<int>&candidates,vector<int>&item,vector<vector<int>>& result,set<vector<int>>&res_set,int sum, int target)
 {
 	if(sum>target || i==num.size()) return;
  	item.push_back(candidate[i]);
 	sum += candidate[i];
 	if(sum==target && res_set.find(item)==res_set.end())
 	{
 		res_set.insert(item);
 		result.push_back(item);
 	}
 	generate(i+1,candidates,item,result,res_set,sum,target); 
 	sum -= candidates[i];
 	item.pop_back();
 	generate(i+1,candidates,item,result,res_set,sum,target); 
 }

在这里插入图片描述
A:在递归生成时,判断左右括号匹配进行剪枝

vector<string> generateParenthesis(int n) 
{
   vector<string> result;
   generate("",n,n,result);
   return result;        
}
void generate(string item,,int left,int right,vector<string>& result)
{
	if(left==0&&right==0)
	{
		result.push_back(item);
		return;
	}
	if(left>0)
		generate(item+'(',left-1,right,result);
	if(right>left)
		genertae(item+')',left,right-1,result);	
}
   

2.N皇后问题

在这里插入图片描述
在这里插入图片描述

#include<iostream>
using namespace std;
#include<vector>
#include<string>

void change_flag(int x, int y, vector<vector<int> >&flag)
{
	int d_x[] = {-1,-1,-1,0,0,1,1,1};
	int d_y[] = {-1,0,1,-1,1,-1,0,1};
	flag[x][y] = 1;
	for(int i=1;i<flag.size();++i)
	{
		for(int j=0; j<8; ++j)
		{
			int newx = x + i*d_x[j];
			int newy = y + i*d_y[j];
			if(newx>=0 && newx<flag.size() && newy>=0 && newy<flag.size())
			{
				flag[newx][newy] = 1;
			}
		}
	}
}

void generate(int k, int n, vector<vector<int> >&flag, vector<string>&item, vector<vector<string> >&result)
{
	if(k==n) 
	{
		result.push_back(item);
		return;
	}
	for(int i=0; i<n; ++i)
	{
		if(flag[k][i]==0)
		{
			vector<vector<int> > tep = flag;
			item[k][i] = 'Q';
			change_flag(k,i,flag);
			cout<<flag[1][1];
			generate(k+1,n,flag,item,result);
			flag = tep;
			item[k][i] = '.';
		}
	}
	
}


vector<vector<string> > solveNQueens(int n) 
{
	vector<string> item;
	vector<vector<string> > result;
	vector<vector<int> > flag;
	for(int i=0; i<n;++i)
	{
		flag.push_back(vector<int>());
		item.push_back("");
		for(int j=0; j<n; ++j)
		{
			flag[i].push_back(0);
			item[i].push_back('.');
		}
	}
	generate(0,n,flag,item,result);
	return result;	
}

3.分治算法

\qquad 将一个规模为N的问题分解为K个规模较小的子问题,这些子问题之间相互独立且与原问题性质相同,求出子问题之后再合并,就可以得到原问题的解。

3.1归并排序

#include<vector>
void merge_sort(vector<int>&nums)
{
	if(nums.size()<2) return;
	int mid = nums.size()>>1;
	vector<vector<int>> sub_left_nums;
	vector<vector<int>> sub_right_nums;
	for(int i=0; i<mid; ++i)
	{
		sub_left_nums.push_back(nums[i]);
	}
	for(int i=mid; i<nums.size(); ++i)
	{
		sub_right_nums.push_back(nums[i]);
	}
	merge_sort(sub_left_nums);
	merge_sort(sub_right_nums);
	nums.clear();
	merge_two_sub(sub_left_nums, sub_right_nums, nums);
}

void merge_two_sub(vector<int>&sub_left_nums,vector<int>&sub_right_nums,vector<int>&nums)
{
	int i=0; 
	int j=0;
	while(i<sub_left_nums.size() && j<sub_right_nums.size())
	{
		if(sub_left_nums[i]<sub_right_nums[j])
		{
			nums.push_back(sub_left_nums[i]);
		}
		else
		{
			nums.push_back(sub_right_nums[j]);
		}
	}
	for(;i<sub_left_nums[i];++i)
	{
		nums.push_back(sub_left_nums[i]);
	}
	for(;j<sub_right_nums[j];++j)
	{
		nums.push_back(sub_right_nums[j]);
	}
}

3.2改造归并排序,求逆序数

在这里插入图片描述


class Solution {
public:
    vector<int> countSmaller(vector<int>& nums) 
    {
        vector<pair<int, int>> vec;
        vector<int> count;
        for(int i=0; i<nums.size(); ++i)
        {
            vec.push_back(make_pair(nums[i],i));
            count.push_back(0);
        }
        merge_sort(vec,count);
        return count;
    }
private:
    void merge_sort_two(vector<pair<int, int>>& sub_vec1, vector<pair<int, int>>& sub_vec2, vector<pair<int,int>>&vec, vector<int>& count)
    {
        int i=0; 
        int j=0;
        while(i<sub_vec1.size() && j<sub_vec2.size())
        {
            if(sub_vec1[i].first <= sub_vec2[j].first)
            {
                count[sub_vec1[i].second] += j;
                vec.push_back(sub_vec1[i]);
                ++i;
            }
            else
            {
                vec.push_back(sub_vec2[j]);
                ++j;
            }
        }
        for(; i<sub_vec1.size();++i)
        {
            count[sub_vec1[i].second] += j;
            vec.push_back(sub_vec1[i]);
        }
        for(; j<sub_vec2.size();++j)
        {
            vec.push_back(sub_vec2[j]);
        }
    }
    void merge_sort(vector<pair<int,int>>& vec, vector<int>&count)
    {
        if(vec.size()<2) return;
        int mid = vec.size()>>1;
        vector<pair<int,int>> sub_vec1;
        vector<pair<int,int>> sub_vec2;
        for(int i=0; i<mid; ++i)
        {
            sub_vec1.push_back(vec[i]);
        }
        for(int i=mid; i<vec.size();++i)
        {
            sub_vec2.push_back(vec[i]);
        }
        merge_sort(sub_vec1,count);
        merge_sort(sub_vec2,count);
        vec.clear();
        merge_sort_two(sub_vec1,sub_vec2,vec,count);
    }
};

对于分治和回溯,目前来看都是基于递归树【二叉树或者多叉树】的构建思路,在复杂度较高的情况下,考虑生成剪枝算法抑制树的形状。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值