问题
题目:[leetcode46]
思路
这个题目要说思路也不难,dfs就好了。每一层试探所有可能的元素,只要有一个满足条件,从这个元素继续dfs就行了。但是也有需要注意的点。
- 剪枝的条件:当前层不能试探上一层试探过的元素。代码实现:建立哈希表,将当前层试探过的哈希表传递给下一层。
- 当前层试探注意点:当前曾上一次的试探不能影响这一次的试探。因为每一层本质是只能有一个元素。所以,每一层的不同试探逻辑上是相互独立的。代码实现:由于每一次试探在逻辑上来说是相互独立的。所以,每次试探的哈希表都是上一层传递过来的,且一样。
搜索树如下:
代码(visit记录元素是否在排列中)
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
std::vector< std::vector<int> > ret;
int sz = nums.size();
if( !sz )
return ret;
std::map< int, bool > visit;
std::vector<int> arr( sz, int() );
dfs( 0, arr, visit, nums, ret );
return ret;
}
private:
void dfs( int depth, std::vector<int>& arr, std::map< int, bool >& visit, const std::vector<int>& nums, std::vector< std::vector<int> >& ret )
{
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
std::map<int, bool> _visit = visit; // 每一层不同的试探逻辑上相互独立,需要获得上一层哈希表
if( _visit.find( nums[i] ) == _visit.end() )
{
arr[depth] = nums[i];
_visit[ nums[i] ] = true;
if( depth == sz - 1 )
ret.push_back( arr );
else
dfs( depth + 1, arr, _visit, nums, ret );
}
}
}
};
测试代码实现:
/*************************************************************************
> File Name: main.cpp
> Author: kang
> Mail:likang@tju.edu.cn
> Created Time: 2016年12月17日 星期六 20时53分55秒
************************************************************************/
#include <iostream>
#include <vector>
#include <map>
class Solution {
public:
std::vector<std::vector<int> > permute( std::vector<int>& nums ) {
std::vector< std::vector<int> > ret;
int sz = nums.size();
if( !sz )
return ret;
std::vector<int> arr( sz, int() );
std::map< int, bool > visit;
dfs( 0, arr, visit, nums, ret );
return ret;
}
private:
void dfs( int depth, std::vector<int>& arr, std::map< int, bool >& visit, const std::vector<int>& nums, std::vector< std::vector<int> >& ret ){
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
std::map< int, bool > _visit = visit;
if( _visit.find( nums[i] ) == _visit.end() )
{
arr[depth] = nums[i];
_visit[ nums[i] ] = true;
if( depth == sz - 1 )
ret.push_back( arr );
else
dfs( depth + 1, arr, _visit, nums, ret );
}
}
}
};
void show( const std::vector<int>& nums ){
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
std::cout << nums[i] << " ";
}
std::cout << std::endl;
}
int main( void )
{
int nums_arr[] = {1, 2, 3};
std::vector<int> nums( nums_arr, nums_arr + 3 );
Solution s;
std::vector< std::vector<int> > ret = s.permute( nums );
int sz = ret.size();
for( int i = 0; i < sz; ++i )
{
show( ret[i] );
}
return 0;
}
这是我做的第一道搜索题目,我补充一下对于上面的这道题目。如何生成所有的序列,没有排列的概念。元素也可以重复。这应该是最完整的搜索树。
思路也很简单,就是在每个位置试探所有的元素,也不剪纸。
void dfs1( int depth, std::vector<int>& arr, const std::vector<int>& nums, std::vector< std::vector<int> >& ret ){
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
arr[depth] = nums[i];
if( depth == sz - 1 )
ret.push_back( arr );
else
dfs1( depth + 1, arr, nums, ret );
}
}
用STL库的next_permutation实现,获取当前排列的下一个排列。返回值为true,如果存在下一个排列。
代码1(STL套路)
#include <algorithm>
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
std::vector< std::vector<int> > ret;
std::sort( nums.begin(), nums.end() ); // 先排序 - 第一个排列
do ret.push_back( nums );
while( std::next_permutation( nums.begin(), nums.end() ) );
return ret;
}
};
思路
当我做下一道题目的时候,发现了这种办法的问题。比如[1,1,2]这个序列,当序列中存在重复元素的时候,这种办法就不行了。因为visit数组记录的是这个元素之前是否出现过,对于不重复的数组来说,元素出现过就代表着这个位置已经使用了。
所以,在求全排列的时候,每一层试探的时候,本质上看的是这个位置,之前是否已经在排列中了,如果不在,可以把这个位置的元素加进来
所以,visit所代表的含义可以是,这个位置的元素是否已经在排列当中。
代码2(visit记录位置是否在排列中)
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
std::vector< std::vector<int> > ret;
std::vector< int > arr( nums.size(), int() );
std::set<int> visit;
dfs( 0, arr, visit, nums, ret );
return ret;
}
private:
void dfs( int depth, std::vector<int>& arr, std::set<int>& visit,
const std::vector<int>& nums, std::vector< std::vector<int> >& ret ){
int sz = nums.size();
for( int i = 0; i < sz; ++i )
{
std::set<int> __visit = visit;
if( __visit.find( i ) == __visit.end() )
{
arr[depth] = nums[i];
__visit.insert( i ); // insert the location of nums[i]
if( sz-1 == depth )
ret.push_back( arr );
else
dfs( depth+1, arr, __visit, nums, ret );
}
}
}
};
思路2
把每个数与他后面的数交换,即可。
注意接口设计,设计n的目的是为了避免当给出char* p = “abc”;这种形式的情形。通用。
代码2
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
int sz = nums.size();
vector<vector<int>> ret;
permute( nums, 0, sz, ret );
return ret;
}
private:
void permute(vector<int>& nums, int depth, int n, vector<vector<int>>& ret){
if(depth == n-1) ret.push_back(nums);
else{
for(int i = depth; i < n; ++i){
swap(nums[depth], nums[i]);
permute(nums, depth+1, n, ret);
swap(nums[depth], nums[i]);
}
}
}
private:
void swap(int& a, int& b){
int t = a;
a = b;
b = t;
}
};