Sovooon's blog

By Sovooon, history, 2 days ago, In English

Subsequences: they’re like the wardrobe combinations of coding—every possible way to arrange your elements without messing up the order. A subsequence is any sequence derived by deleting some (or no) elements of the array without changing the order of the remaining elements. This is my first blog on Codeforces ^-^ In this blog, I’ll guide you through the process of generating all subsequences of a given array using recursion. Along the way, we’ll explore the logic, implementation, and common pitfalls, with just the right mix of fun and formality.


What Are Subsequences?

A subsequence is any sequence derived from an array by deleting some (or no) elements, without changing the order of the remaining elements.

For example, given the array [1, 2, 3], the subsequences are: [], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3] Notice how the order is preserved, and yes, the empty set [] is part of the deal—because sometimes doing nothing is a valid choice. :P


The Recursive Approach

Recursion is basically your lazy friend—it works by delegating smaller parts of the problem to itself. For subsequences, here’s the plan:

  1. At every index, you have two choices: — Pick the element: Include it in the current subsequence. — Don’t pick the element: Skip it and move forward.
  2. Keep repeating this until you’ve processed all elements.
  3. At the end, print (or store) the current subsequence.

Visualizing the Recursion Tree

For the array [1, 2, 3], the recursion tree looks like this:

                             []
                          /       \
                      [1]            []
                    /     \        /     \
               [1,2]      [1]   [2]       []
             /    \      /   \  /   \     /   \
       [1,2,3] [1,2] [1,3] [1] [2,3] [2] [3]  []
  • At the root: Start with the empty set [].
  • First level: For each element, decide whether to pick or not pick it.
  • Second level: Repeat the same decision for the next element.
  • Third level: Continue until all elements are processed.
  • Leaf nodes: Represent the final subsequences.

By the time the recursion is complete, you’ll have all possible subsequences.


Code Implementation

Here’s how to bring this concept to life with C++:

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

void generateSubsequences(int idx, int arr[], int n, vector<int> &ds) {
    // Base case: If we’ve processed all elements
    if (idx == n) {
        if (ds.empty()) {
            cout << "{}"; // Represent the empty subsequence
        } else {
            for (auto it : ds) {
                cout << it << " ";
            }
        }
        cout << endl;
        return;
    }

    // Pick the current element
    ds.push_back(arr[idx]);
    generateSubsequences(idx + 1, arr, n, ds);

    // Don’t pick the current element (backtrack)
    ds.pop_back();
    generateSubsequences(idx + 1, arr, n, ds);
}

int main() {
    int arr[] = {1, 2, 3}; 
    int n = sizeof(arr) / sizeof(arr[0]); // Size of the array
    vector<int> ds; // To store the current subsequence, we are passing this data structure (ds)

    generateSubsequences(0, arr, n, ds);
    return 0;
}

How It Works

Let’s run this on the array [1, 2, 3]: 1. Start with Index 0 (1): — Pick 1 → Add 1 to the current subsequence and move forward. — Don’t Pick 1 → Skip 1 and move forward.

  1. Move to Index 1 (2): — For both cases from the previous step: — Pick 2 → Add 2 to the subsequence. — Don’t Pick 2 → Skip 2.

  2. Move to Index 2 (3): — Again, pick or skip 3 for each branch.

By the time you reach the base case (idx == n), all possible subsequences will be printed.


Output

For the input arr = [1, 2, 3], the output will be: 1 2 3 1 2 1 3 1 2 3 2 3 {}


Common Mistakes (and How to Avoid Them)

  1. Forgetting to Backtrack: If you don’t pop_back() after picking an element, your subsequences will contain extra elements from previous recursive calls. Backtracking ensures each branch of the tree starts fresh.
  2. No Base Case: Without the base case (idx == n), your recursion will run forever and probably crash harder than your first Codeforces contest. >-<
  3. Printing Inside Loops: Make sure to print subsequences only after reaching the base case.

>>

Try modifying this code to:

  1. Count the number of subsequences.

  2. Store the subsequences in a 2D vector instead of printing them directly...

Feel free to share your thoughts or questions below. Happy coding! :D


  • Vote: I like it
  • +11
  • Vote: I do not like it

»
2 days ago, # |
  Vote: I like it 0 Vote: I do not like it

I don't want to end up as rude but, how is this useful and isn't this trivial?

  • »
    »
    34 hours ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    -<

  • »
    »
    34 hours ago, # ^ |
      Vote: I like it +12 Vote: I do not like it

    I suppose OP wants some contribution points.

»
34 hours ago, # |
Rev. 3   Vote: I like it +4 Vote: I do not like it

it's basic coding of complete search, not something unique

»
30 hours ago, # |
  Vote: I like it +25 Vote: I do not like it

world's most chatgpt blog ever

»
25 hours ago, # |
  Vote: I like it +1 Vote: I do not like it

Even though people might find this as a "Basic" or "Anyone could have googled this" blog. But for me it kinda makes sense tho...

ofc it's not as advanced as you want to see in a CP website's blog. But you cant deny that content like this belongs to CF. (making CF more newbie friendly).