人生的第一次面试,一家做算法的小公司,面试官人挺好,但我发挥的太差了……
前面几到和数据库有关的业务题,就先不说了,哎。
有一道看似很简单的算法题,竟然做不出来……
看到这题,我首先想到了剑指offer的一道题目:
class Solution {
public:
vector<string> Permutation(string str) {
vector<string>ans;
if (str.size()==0)return ans;
dp(ans,str,0); // & * ??
sort(ans.begin(),ans.end()) ;
return ans;
}
void dp(vector<string>&ans,string str,int begin)
{
if (begin==str.size())
{
ans.push_back(str);
return ;
}
for (int i =begin;i<str.size();i++)
{
if (i!=begin && str[i]==str[begin])continue; //考虑重复!!
swap(str[begin],str[i]);
dp(ans,str,begin+1);
swap(str[begin],str[i]);
}
}
};
class zh{
public:
vector<string>zuhe(string str)
{
vector<string>ans;
vector<char>tmp;
if (str.size()==0)return ans;
for (int i=1;i<=str.size();i++)
{
dp(ans,tmp,str,0,i);
}
return ans;
}
void dp(vector<string>&ans,vector<char>&tmp,string str,int begin,int num) // num : the number of combion
{
if (num==0 )
{
string s = "";
for (int i=0;i<tmp.size();i++)
{
s+=tmp[i];
}
ans.push_back(s);
return;
}
if (begin==str.size())return ;
tmp.push_back(str[begin]);
dp(ans,tmp,str,begin+1,num-1);
tmp.pop_back();
dp(ans,tmp,str,begin+1,num);
}
};
位运算,所有1,0的组合,即为所有字符的组合
class wei{
public:
vector<string>zuhe(string str)
{
vector<string>ans;
set<string>se;
if (str.size()==0)return ans;
for (int i=1;i<(1<<str.size());i++)
{
mj(se,i,str); // 2 ** (n-1)
}
for (set<string>::iterator it= se.begin();it!=se.end();it++ )
{
ans.push_back(*it);
}
return ans;
}
void mj(set<string>& ans, int n,string str)
{
string tmp = "";
for (int i=0;i<str.size();i++)
{
if ((1<<i)&n)
{
tmp+=str[i];
// cout<<"--"<
}
}
ans.insert(tmp);
}
};
leetcode 一道组合题目,规定了返回组合数的长度。
Input: n = 4, k = 2
Output:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
目前只是在之前位运算的基础上加了一个判断条件,复杂度依然为O(n**2),后面再优化吧
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int> >ans;
for (int i=1;i<(1<<n);i++)
{
vector<int>v;
for (int j=0;j<n;j++)
{
if ((1<<j)&i)
{
v.push_back(j+1);
}
}
if (v.size()==k)
{
ans.push_back(v);
}
}
return ans;
}
};
对于结构体
总结起来,排列,从第一个数开始,后面每个数和其交换,固定第一个数,递归的作用于后面的子序列;终止条件,begin==str.size()-1;
组合,外层的一个for循环决定要组合多少个数;对于每个固定的数,从0开始,判断当前数是否加入进去。 终止条件,number = 0 , 注意 begin 不要越界。
#include
#include
#include
using namespace std;
struct node{
char name;
int number;
node(char s,int n):name(s),number(n){
}
};
bool cmp(struct node a,struct node b)
{
return a.number<b.number;
}
class solve_bt{
public:
vector<vector<node> >pl(vector<node>str)
{
vector<vector<node> >ans;
if (str.size()==0)return ans;
dg(ans,str,0);
return ans;
}
void dg(vector<vector<node> >&ans,vector<node>str,int begin)
{
if (begin==str.size()-1)
{
// sort(str.begin(),str.end(),cmp);
ans.push_back(str);
return ;
}
for (int i=begin;i<str.size();i++)
{
if (i!=begin && str[i].name==str[begin].name)continue;
swap(str[begin],str[i]);
dg(ans,str,begin+1) ;
swap(str[begin],str[i]);
}
}
};
class solve_zh{
public:
vector<vector<node> >zh(vector<node>str)
{
vector<vector<node> >ans;
if (str.size()==0)return ans;
vector<node>tmp;
for (int i=1;i<=str.size();i++)
{
dg(ans,tmp,str,0,i);
}
return ans;
}
void dg(vector<vector<node> >&ans,vector<node>&tmp,vector<node>str,int begin,int number)
{
if (number==0)
{
sort(tmp.begin(),tmp.end(),cmp);
// for (int i=0;i
// cout<
ans.push_back(tmp);
return ;
}
if (begin==str.size())return ;
tmp.push_back(str[begin]);
dg(ans,tmp,str,begin+1,number-1);
tmp.pop_back();
dg(ans,tmp,str,begin+1,number);
}
};
int main()
{
node a('a',2);
node b('b',1);
node c('c',3);
vector<node>str;
str.push_back(a);
str.push_back(b);
str.push_back(c);
swap(str[0],str[1]);
for (int i=0;i<str.size();i++)
{
cout<<str[i].name<<endl;
}
cout<<"---"<<endl;
// solve_bt bt;
// vector >ans= bt.pl(str);
solve_zh z;
vector<vector<node> >ans = z.zh(str);
for (int i=0;i<ans.size();i++)
{
for (int j=0;j<ans[i].size();j++)
{
cout<<ans[i][j].name;
}
cout<<endl;
}
return 0;
}
----------------更------------
关于,排列,如果有重复元素,我上面的解法应该是错的 ,参考:
https://www.cnblogs.com/grandyang/p/4359825.html
https://leetcode.com/problems/permutations-ii/description/
暂时还是用 set吧……
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
set<vector<int> >ans;
int n = nums.size();
// if (n==0)return ans;
solve(ans,nums,0,n);
return vector<vector<int> >(ans.begin(),ans.end());
}
void solve(set<vector<int> >&ans,vector<int>&nums,int cur,int n)
{
if (cur==n)
{
// ans.push_back(nums);
ans.insert(nums);
return ;
}
for (int i=cur;i<n;i++)
{
if (i!=cur && nums[i]==nums[cur])continue;
swap(nums[cur],nums[i]);
solve(ans,nums,cur+1,n);
swap(nums[cur],nums[i]);
}
return;
}
};
关于组合,还有另外一种dfs的做法,形式上和排序相似,注意,push(i) 以及 solve(i+1)的做法:
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int> >ans;
vector<int>tmp;
if (n<=0|| k<=0)return ans;
solve(ans,tmp,1,k,n);
return ans;
}
void solve(vector<vector<int> >& ans,vector<int>& tmp,int cur,int k,int n)
{
if (tmp.size()==k)
{
ans.push_back(tmp);
return ;
}
for (int i=cur;i<=n;i++)
{
// if (cur>n)return;
tmp.push_back(i);
solve(ans,tmp,i+1,k,n);
tmp.pop_back();
// solve(ans,tmp,cur+1,k,n);
}
return;
}
-------------------
剪枝的用法: 每次能用的数 和剩余的k有关
void solve(vector<vector<int> >& ans,vector<int>& tmp,int cur,int k,int n)
{
if (k==0)
{
ans.push_back(tmp);
return ;
}
for (int i=cur;i<=n-k+1;i++)
{
// if (cur>n)return;
tmp.push_back(i);
solve(ans,tmp,i+1,k-1,n);
tmp.pop_back();
// solve(ans,tmp,cur+1,k,n);
}
return;
}
};
leetcode上一道算是组合的题吧,注意题中要求的是,组合出一组数(改组合数是可以重复用的),其和为某值。
https://leetcode.com/problems/combination-sum/
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int> >ans;
vector<int>tmp;
// int n = candidates.size();
// if (n<=0)return ans;
// for (int i=1;i<=n;i++)
// {
solve(ans,tmp,candidates,0,target);
// }
return ans;
}
void solve(vector<vector<int> >&ans,vector<int>&tmp,vector<int>&candidates,int cur,int target)
{
// if (target<0)return;
if (target==0)
{
ans.push_back(tmp);
}
else if (target>0)
{
for (int j=cur;j<candidates.size();j++)
{
if (candidates[j]<=target)
{
tmp.push_back(candidates[j]);
solve(ans,tmp,candidates,j,target-candidates[j]);
tmp.pop_back();
}
}
// if (cur>=n)return;
// tmp.push_back(candidates[cur]);
// solve(ans,tmp,candidates,cur+1,k-1,n,target);
// tmp.pop_back();
// solve(ans,tmp,candidates,cur+1,k,n,target);
}
}
};
https://leetcode.com/problems/combination-sum-ii/
组合二。有两个地方,一个是不能重复利用数组的数,那就从 i+1 递归;
二是数组中有重复的数,那可以先排序,然后 在for循环的开始,判断是否和之前重复
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int> >ans;
vector<int>tmp;
sort(candidates.begin(),candidates.end());
solve(ans,tmp,candidates,0,target);
return ans;
}
void solve(vector<vector<int>>&ans,vector<int>&tmp,vector<int>& candidates,int cur,int target)
{
if (target==0)
{
ans.push_back(tmp);
}
else if (target>0)
{
for (int i=cur;i< candidates.size();i++)
{
if (i>cur && candidates[i]==candidates[i-1])continue;
tmp.push_back(candidates[i]);
solve(ans,tmp,candidates,i+1,target-candidates[i]);
tmp.pop_back();
}
}
}
};