image.png

思路:回溯

  • 我的解法和官方题解不一样,官方题解更加直观,但是我的解法建立的树更加小
  • 官方题解的做法是“二叉树式的组合回溯”,左孩子选,右孩子不选
  • 我的解法是“数组的最后一个元素作为叶子节点的组合回溯”方法,使用了for循环
  • 脑力里面要有图,两张图的区别要搞清楚

image.png
image.png

代码:

  1. class Solution {
  2. public:
  3. void backTrack(vector<int>& t, vector<vector<int>>& ans, int cur, vector<int>& nums) {
  4. ans.push_back(t);
  5. if (cur == nums.size()) {
  6. return;
  7. }
  8. for (int i = cur; i < nums.size(); ++i) {
  9. t.push_back(nums[i]);
  10. backTrack(t, ans, i + 1, nums);
  11. t.pop_back();
  12. }
  13. }
  14. vector<vector<int>> subsets(vector<int>& nums) {
  15. vector<int> t;
  16. vector<vector<int>> ans;
  17. backTrack(t, ans, 0, nums);
  18. return ans;
  19. }
  20. };

思路2:位运算暴搜

  • 枚举所有情况,子集问题近似于二进制枚举的本质,逐个枚举,遍历所有子集
  • 枚举所有情况

    1. for (int S = 0; S < (1 << n); ++S) {
  • 从低位开始检查是否选用当前元素

  1. for (int i = 0; i < n; i++) {
  2. if (S & (1 << i)) {
  3. t.push_back(nums[i]);
  4. }
  5. }

代码2

  1. class Solution {
  2. public:
  3. vector<vector<int>> subsets(vector<int>& nums) {
  4. vector<vector<int>> ans;
  5. int n = nums.size();
  6. for (int S = 0; S < (1 << n); ++S) {
  7. vector<int> t;
  8. for (int i = 0; i < n; i++) {
  9. if (S & (1 << i)) {
  10. t.push_back(nums[i]);
  11. }
  12. }
  13. ans.push_back(t);
  14. }
  15. return ans;
  16. }
  17. };