递归的开篇

首先我们看看
1.归并排序写法

#include <iostream>
#include<vector>
#include <ctime>
#include<algorithm>
using namespace std;

#define num 100
void Merge(vector<int> &arr, int start, int end,int mid, vector<int> &temparr)
{
	int i_start = start;
	int i_end = mid;
	int j_start = mid + 1;
	int j_end = end;

	int length = 0;
	//合并两个有序序列(为什么就有序了)  思考!!!
	while (i_start<= i_end&& j_start<= j_end)
	{
		if (arr[i_start]< arr[j_start])
		{
			temparr[length] = arr[i_start];
			length++;
			i_start++;
		}
		else
		{
			temparr[length] = arr[j_start];
			length++;
			j_start++;
		}
	}

	while (i_start<= i_end)
	{
		temparr[length] = arr[i_start];
		length++;
		i_start++;
	}

	while (j_start <= j_end)
	{
		temparr[length] = arr[j_start];
		length++;
		j_start++;
	}

	//辅助空间数据覆盖到原空间
	for (int i=0;i<length;i++)
	{
		arr[start+i]=temparr[i];

	}

}


void MergeSort(vector<int> &arr, int start, int end, vector<int> &temparr)
{

	if (start>=end)
	{
		return;
	}
	//划分到最后是每一个里面只有一个数据 
	int mid = (start + end) / 2;
	MergeSort(arr,start,mid, temparr);
	MergeSort(arr, mid+1, end, temparr);

	Merge(arr, start, end, mid, temparr);
}
int main()
{
	//int num;
	//cin >> num;

	vector<int> arr(num, 0);
	srand((int)time(0));
	for (int i = 0; i < num; i++)
	{
		arr[i] = rand() % 100;
	}
	for (int i = 0;i < arr.size();i++)
	{
		cout << arr[i] << "  ";
	}

	cout << endl;


	//归并排序(从小到大)


	//由于归并排序需要申请额外空间大小,因空间复杂度是O(n)
	vector<int> temparr(num, 0);


	MergeSort(arr,0,arr.size() - 1,temparr);



	for (int itemp : arr)
		cout << itemp << "  ";


	return 0;
}

2.1然后再看看求某一个节点到根结点的长度

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

struct  Node
{
	int data;
	Node * lchild;
	Node * rchild;
};

vector<int> path;
bool flag2 = false;
void getNodePath(Node* root, int x) {

	if (root == NULL) return;
	if (flag2) return;
	path.push_back(root->data);
	if (root->data == x) {
		for (int x : path) { //输出栈的内容
			printf("%d ", x);
		}
		flag2 = true;
		return;
	}
	getNodePath(root->lchild, x);
	getNodePath(root->rchild, x);
	path.pop_back();
}

拓展
2.1为了和后面的
全排列问题以及皇后问题进行统一
我们不妨改改,由于二叉数最多有两个孩子,后面的全排列以及皇后“孩子”可能有多个。

bool get_return(Node* &node,bool &flag,int x)
{
	if (node->data == x) {
		for (int x : path) { //输出栈的内容
			printf("%d ", x);
		}
		flag = true;
		
	}
	return flag;

}

vector<int> path;
bool flag2 = false;
void getNodePath(Node* root, int x) {
	if (root == NULL) return;
	if (flag2) return;	for (int i = 0;i < 1;i++)//由于二叉树最多只有两种可能  后面的全排列以及皇后是有多种可能的
	{
		if (i == 0)
		{
			if (get_return(root, flag2,x)==true)//理解为剪枝
			{
				return;
			}
			path.push_back(root->data);
			getNodePath(root->lchild, x);
			path.pop_back();
		}
		else
		{
			if (get_return(root, flag2, x) == true)理解为剪枝
			{
				return;
			}
			path.push_back(root->data);
			getNodePath(root->rchild, x);
			path.pop_back();
		}

	}
}

3.然后我们再看看,leetcode排列问题
首先我们写一种好理解的

class Solution {
    private:
 
    void dfs(int index,vector<int>& nums,vector<bool> &isUse_v,vector<vector<int>> &result_vv,vector<int>&temp_v)
    {
        if(index>=nums.size())
        {
            result_vv.push_back(temp_v);
            return;
        }

        for(int i=0;i<nums.size();i++)
        {
            if(isUse_v[i]==true)  continue;
            temp_v.push_back(nums[i]);
            isUse_v[i]=true;


            dfs(index+1,nums,isUse_v,result_vv,temp_v);

            isUse_v[i]=false;
            temp_v.pop_back();

        }
    }


public:
    vector<vector<int>> permute(vector<int>& nums) {

        vector<vector<int>>result_vv;
        vector<int>temp_v;
        vector<bool> isUse_v(nums.size(),false);
        dfs(0,nums,isUse_v,result_vv,temp_v);

        return result_vv;
    }
};

我们可以发现,我们必须申请比较多的变量才能跳过引用问题。

拓展
3.2因此我们使用引用后的写法;

根据leetcode自带函数写全排列,每次都传引用

class Solution {
    private:
 
    void dfs(int index,vector& nums,vector &isUse_v,vector> &result_vv,vector&temp_v)
    {
        if(index>=nums.size())
        {
            result_vv.push_back(temp_v);
            return;
        }

        for(int i=0;i        {
            if(isUse_v[i]==true)  continue;
            temp_v.push_back(nums[i]);
            isUse_v[i]=true;            dfs(index+1,nums,isUse_v,result_vv,temp_v);

            isUse_v[i]=false;
            temp_v.pop_back();

        }
    }public:
    vector> permute(vector& nums) {

        vector>result_vv;
        vectortemp_v;
        vector isUse_v(nums.size(),false);
        dfs(0,nums,isUse_v,result_vv,temp_v);

        return result_vv;
    }
};

**4.**说到这里就不得不提 leetcode全排列(有重复) 只需要剪枝就可以了
代码是根据上面代码改的

class Solution {
    private:
 
    void dfs(int index,vector<int>& nums,vector<bool> &isUse_v,vector<vector<int>> &result_vv,vector<int>&temp_v)
    {
        if(index>=nums.size())
        {
            result_vv.push_back(temp_v);
            return;
        }

        for(int i=0;i<nums.size();i++)
        {
            if(isUse_v[i]==true)  continue;
            //就是相邻重复元素只需要遍历一次就可以了。
            //isUse_v[i-1]==false与isUse_v[i-1]==true 在下面if中都是可以了,两种意义是不同的,一个是同层剪枝,一个上下剪枝
            if(i>0&&nums[i]==nums[i-1]&&isUse_v[i-1]==false) continue;
            
            temp_v.push_back(nums[i]);
            isUse_v[i]=true;
            dfs(index+1,nums,isUse_v,result_vv,temp_v);
            isUse_v[i]=false;
            temp_v.pop_back();

        }
    }

**5.**当然还有个经典的N皇后问题

N皇后问题问题来了

//回溯+dfs

class Solution {
    //首先输出有多少可能
    private:
    
    void dfs(int index,int N,vector<int> &rowToclumn,vector<vector<string>> &result_vv)
    {
        if(index>=N)
        {
            //我们使用简单点的
            vector<string> temp_v;
            
             for(int i=0;i<N;i++)
            {   
                string temp(N,'.');

                int Q_index=rowToclumn[i];
                temp.replace(Q_index,1,"Q");
               // temp[Q_index]='Q';
                temp_v.push_back(temp);
            }
            
            result_vv.push_back(temp_v);

        }

        for(int i=0;i<N;i++)
        {
            //cout<<"i="<<i<<" ";
            if(getLegal(rowToclumn,index ,i)==false)   continue;//与前面的皇后有冲突,就进行下一个位置的判定

            rowToclumn.push_back(i);//这个就相当于全排列中,对于每个元素是否使用过,起到是否符合条件作用

            dfs(index+1,N,rowToclumn,result_vv);

            rowToclumn.pop_back();//与push相对应
        }

    }

  bool getLegal( vector<int> rowToclumn,int row,int colum)//这个代表判断每个是不是 其中每个皇后都不同行、不同列,也不在对角线上
  {
      for(int one_row=0;one_row<rowToclumn.size();one_row++)
      {
          if(rowToclumn[one_row]==colum||(one_row+rowToclumn[one_row])==(row+colum)||(one_row-rowToclumn[one_row])==(row-colum))
          return false;
      }

    return true;
  }
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> result_vv;
        //简单点
      

        vector<int> rowToclumn;
        dfs(0,n,rowToclumn,result_vv);

        for(auto it=rowToclumn.begin();it!=rowToclumn.end();it++)
        {
            cout<<*it<< "  ";
        }

        return result_vv;
    }
};

6.组合问题
给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

示例:

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

代码:

class Solution {
private:
    vector<vector<int>> result_vv;
    vector<int> restore;//存数据的
    void _combine(int k,vector<int> &nums,int current_index)
    {
        //N是代表个数 
        //nums是代表着数据源
        //current_index是代表现在访问的位置
        if(restore.size()==k)
        {
            result_vv.push_back(restore);     
            return ;
        }
   
        for(int i=current_index;i<nums.size();i++)
        {
            restore.push_back(nums[i]);

            //current_index;//组合问题就是这样

            _combine(k,nums,i+1);

            restore.pop_back();
            
        }
        return;
    }


public:
    vector<vector<int>> combine(int n, int k)
    {
        vector<int> restore;
        vector<int> nums;
        for(int i=0;i<n;i++)
        {
            nums.push_back(i+1);
        }
        int current_index=0;
        _combine(k, nums,current_index);//0代表从第0位置搜索
        return result_vv;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值