逐步生成结果-非数值型问题(组合问题、排列问题)

一、合法括号

初始定义“()”是一个可消除的合法括号,此时设m=1。当m增加为2时,要在此基础上新增加一对括号,但是新生成括号对要求是可完全消除的(即从左到右,相邻的左右括号可以消除),也就是消除完是空串。求m=n时,有多少符合条件的串?

递归:

# include<iostream>
# include<string>
# include<vector>
# include<set>

using namespace std;

set<string> Brackets(int n) {
	set<string>cur_str;
	if (n == 1) {
		cur_str.insert("()");
		return cur_str;
	}
	set<string>new_str = Brackets(n - 1);
	for (auto it = new_str.begin(); it != new_str.end(); it++) {
		cur_str.insert("()" + *it);
		cur_str.insert(*it + "()");
		cur_str.insert("(" + *it + ")");
	}
	return cur_str;
}

int main(void) {
	int n;
	cin>> n;

	set<string>ans;
	ans=Brackets(n);

	for (auto it = ans.begin(); it != ans.end(); it++) {
		cout << *it << endl;
	}
	return 0;
}

对于当前次操作来说,一共有三类方法:左,右,包
(1)放在cur的左边
(2)放在cur的右边
(3)包住cur

迭代:

# include<iostream>
# include<string>
# include<vector>
# include<set>

using namespace std;

int main(void) {
	int n;
	cin>> n;

	set<string>cur_str;
	cur_str.insert("()");

	for (int i = 1; i < n; i++) {
		set<string>new_str;
		for (auto it = cur_str.begin(); it != cur_str.end(); it++) {
			new_str.insert("()" + *it);
			new_str.insert(*it + "()");
			new_str.insert("(" + *it + ")");
		}
		cur_str=new_str;
	}

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



	return 0;
}


二、子集个数(组合问题)

求一个集合的子集?

递归:

#include<iostream>  
#include<set>  
#include<vector>  
#include<algorithm>

using namespace std;

set<set<int>> GetSet(vector<int>& arr, int n, int curIndex) {
    set<set<int>> new_set;

    if (curIndex == 0) {
        set<int>emotyJ= {};
        set<int>firstJ = { arr[0] };
        new_set.insert(emotyJ); // 插入空集合  
        new_set.insert(firstJ); // 插入第一个元素的集合  
        return new_set;
    }

    set<set<int>> cur_set = GetSet(arr, n, curIndex - 1);

    // 将之前的子集加入到 new_set 中  
    for (auto a : cur_set) {
        new_set.insert(a); // 插入当前集合  

        set<int> cur = a; // 复制当前集合  
        cur.insert(arr[curIndex]); // 插入当前索引的元素  
        new_set.insert(cur); // 插入新的集合  
    }

    return new_set;
}

set<set<int>> ChildSet(vector<int>& arr) {
    sort(arr.begin(), arr.end());
    return GetSet(arr, arr.size(), arr.size() - 1);
}

int main(void) {
    vector<int> arr = { 1, 2, 3,4};

    set<set<int>> ans = ChildSet(arr);

    int n = ans.size();
    cout << "子集个数:" << n << endl;

    // 输出子集  
    for (auto sub_set : ans) {
        cout << "{ ";
        for (auto elem : sub_set) {
            cout << elem << " ";
        }
        cout << "}" << endl;
    }

    return 0;
}

无非就是加不加新元素

迭代:

#include<iostream>  
#include<set>  
#include<vector>  
#include<algorithm>

using namespace std;

set<set<int>> GetSet(vector<int>& arr, int n, int curIndex) {

    set<set<int>> cur_set;
    set<int> empty_set = {};
    cur_set.insert(empty_set);
    
    for (int i = 0; i < n; i++) {
        set<set<int>> new_set;
        
        // 将之前的子集加入到 new_set 中  
        for (auto a : cur_set) {
            new_set.insert(a); // 插入当前集合  

            set<int> cur = a; // 复制当前集合  
            cur.insert(arr[i]); // 插入当前索引的元素  
            new_set.insert(cur); // 插入新的集合  
        }
        cur_set=new_set;
	}
    return cur_set;
}

set<set<int>> ChildSet(vector<int>& arr) {
    sort(arr.begin(), arr.end());
    return GetSet(arr, arr.size(), arr.size() - 1);
}

int main(void) {
    vector<int> arr = { 1, 2, 3, 4};

    set<set<int>> ans = ChildSet(arr);

    int n = ans.size();
    cout << "子集个数:" << n << endl;

    // 输出子集  
    for (auto sub_set : ans) {
        cout << "{ ";
        for (auto elem : sub_set) {
            cout << elem << " ";
        }
        cout << "}" << endl;
    }

    return 0;
}

与上面类似

位运算迭代法:

无非就是取或者不取

#include<iostream>  
#include<set>  
#include<vector>  
#include<algorithm>

using namespace std;

set<set<int>> GetSet(vector<int>& arr, int n, int curIndex) {

    set<set<int>> res;
    for (int i = 0; i < (1 << n); i++) {
        set<int>cur;
        int val = i;
        int index = curIndex;
        if (val == 0) {
			res.insert(cur);
			continue;
		}
        while (val >0) {
            if (val & 1) {
				cur.insert(arr[index]);
			}
			val >>= 1;
			index--;
        }
        res.insert(cur);
    }
    return res;
}

set<set<int>> ChildSet(vector<int>& arr) {
    sort(arr.begin(), arr.end());
    return GetSet(arr, arr.size(), arr.size() - 1);
}

int main(void) {
    vector<int> arr = { 1, 2, 3};

    set<set<int>> ans = ChildSet(arr);

    int n = ans.size();
    cout << "子集个数:" << n << endl;

    // 输出子集  
    for (auto sub_set : ans) {
        cout << "{ ";
        for (auto elem : sub_set) {
            cout << elem << " ";
        }
        cout << "}" << endl;
    }

    return 0;
}

三、排列序列(排列问题)

每个都要取,但是只能取一次

递归:

#include<iostream>  
#include<vector>  
#include<string>
#include<algorithm>

using namespace std;

vector<string> GetChild(int n,int curIndex){
    vector<string> now;
    vector<string> cur;
    if (curIndex == 1) {  
        now.push_back("1");
        cur=now;
        return cur;
    }

    cur=GetChild(n, curIndex - 1);
        
    for (string temp : cur) {
        now.push_back(temp + to_string(curIndex));
        now.push_back(to_string(curIndex) + temp);

        for (int j = 1; j < temp.size(); j++) {
            now.push_back(temp.substr(0, j) + to_string(curIndex) + temp.substr(j));
        }
    }
    cur = now;

	return cur;
}

int main(void) {
    int n,k;
    cin >> n>>k;
    // 获取子集
    vector<string>ans = GetChild(n,n); // 存放子集的数组
    
    
    //排序
    sort(ans.begin(), ans.end());

    // 输出子集个数
    int n_ = ans.size();
    cout << "子集个数:" << n_ << endl;

    // 输出子集  
    for (auto sub_set : ans) {
        cout << sub_set << endl;
    }
    cout<<endl;

    // 输出第k个子集
	cout << ans[k - 1];

    return 0;
}

和上次说的一样,递归其实就是老板思维,我只需要看最后一次就行了,其他的由员工去完成。
对于当前次操作来说,一共有三类方法。

  • (1)放在cur的前面
  • (2)放在cue的后面
  • (3)插在cur的中间(cur.size()-1个间隔)

和合法括号有点类似。


迭代:

#include<iostream>  
#include<vector>  
#include<string>
#include<algorithm>

using namespace std;

vector<string> GetChild(int n) {
    vector<string> cur;
    cur.push_back("1");
    
    for (int i = 2; i <= n; i++) {
        vector<string> now;
        
        for (string temp : cur) {
            now.push_back(temp + to_string(i));
            now.push_back(to_string(i) + temp);

            for (int j = 1; j < temp.size(); j++) {
                now.push_back(temp.substr(0, j) + to_string(i) + temp.substr(j));
            }
        }
      
        cur = now;
    }
	return cur;
}

int main(void) {
    int n,k;
    cin >> n>>k;
    // 获取子集
    vector<string>ans = GetChild(n); // 存放子集的数组
    
    
    //排序
    sort(ans.begin(), ans.end());

    // 输出子集个数
    int n_ = ans.size();
    cout << "子集个数:" << n_ << endl;

    // 输出子集  
    for (auto sub_set : ans) {
        cout << sub_set << endl;
    }
    cout<<endl;

    // 输出第k个子集
	cout << ans[k - 1];

    return 0;
}

主要就是将递归的过程用循环代替,其余没有什么改变。

不要忘了排序,保证最后结果是字典序。


另一种迭代思路:

#include<iostream>  
#include<vector>  
#include<algorithm>

using namespace std;

vector<vector<int>> GetChild(int n) {
    int row = n;
    vector<vector<int>> cur;
    
    for (int i = 0; i < row; i++) {
        vector<int> temp(n, 0);
        temp[i] = 1;
        cur.push_back(temp);
    }
    
    for (int i = 2; i <= n; i++) {
        vector<vector<int>> now;
        vector<int> temp;
        
        for (int j = 0; j < cur.size(); j++) {
            for (int k = 0; k < n; k++) {
                temp = cur[j];
                if (temp[k] == 0) {
                    temp[k] = i;
                    now.push_back(temp);
                }
            }
            
        }
        cur = now;
    }
	return cur;
}

int main(void) {
    int n,k;
    cin >> n>>k;
    // 获取子集
    vector<vector<int>>ans = GetChild(n); // 存放子集的数组
    
    
    //排序
    sort(ans.begin(), ans.end());

    // 输出子集个数
    int n_ = ans.size();
    cout << "子集个数:" << n_ << endl;

    // 输出子集  
    for (auto sub_set : ans) {
        cout << "{ ";
        for (auto elem : sub_set) {
            cout << elem << " ";
        }
        cout << "}" << endl;
    }

    // 输出第k个子集

    for (auto elem : ans[k - 1]) {
		cout << elem;
	}
   

    return 0;
}


这种迭代法控制的是数字的位置,而不是当前数字是哪个。
通过枚举所有数字可能的位置来求排列。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐远方的梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值