Sign in
Log inSign up
Subset/Subsequence Pattern

Subset/Subsequence Pattern

Divyajyoti Ukirde's photo
Divyajyoti Ukirde
·Feb 22, 2022·

2 min read

Subset

Subset patterns deal with Permutation and Combinations.

e.g.

"abc" -> [ "abc", "acb", "bac", "bca", "cab", "cba" ] //permutations
[1,2,3] -> [ [],[1], [2], [3], [1,2], [2,3], [1,3], [1,2,3] ]

We can solve permutations with the help of subset pattern

Time Complexity - O(n!)

let arr = [];
function permutations(processedStr='',unprocessedStr=''){

    if(unprocessedStr.length == 0){ // string processed
        arr.push(processedStr);
        return;
    }

    // recursion calls increase with increase in processed string length
    for(let i=0;i<=processedStr.length;i++){ 
        // processedStr = "a" ; unprocessedStr = "bc"
        // newString = ""(0,0) + "b" + "a"(0,1)
        // newString = "a"(0,1) + "b" + ""(1,1)
        let newString = processedStr.slice(0,i) + unprocessedStr[0] + processedStr.slice(i,processedStr.length);
        permutations(newString, unprocessedStr.substring(1));
    }

}

permutations("","abc");
console.log(arr); // [ "abc", "acb", "bac", "bca", "cab", "cba" ]

Wherever you see a question that tells you to take some elements and remove some elements, that is your subset pattern problem

Iterative approach

function iterativeSubset(unprocessedArr=[]){
    let processedArr = [];

    // start with empty array
    if(unprocessedArr.length > 0){
        processedArr.push([]) // push empty array
    }

    for(let i=0;i<unprocessedArr.length;i++){ // for every pass #subsets gets doubled
        let copyOfProcessed = [...processedArr];
        for(let j=0;j<copyOfProcessed.length;j++){
            copyOfProcessed[j] = copyOfProcessed[j].concat([unprocessedArr[i]]);
        }
        processedArr = processedArr.concat(copyOfProcessed);
    }

    return processedArr;
}

ans = iterativeSubset([1,2,3]);
console.log(ans); // [[],[1], [2], [3], [1,2], [2,3], [1,3], [1,2,3]]

Subsequence

A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters

Let's look at subsequence of string -

"abc" -> "a", "b", "c", "ab", "bc", "ac", "abc"

The recursion call can be visualised as follows:

image.png

We take processed string, unprocessed string and the array that is to be returned as arguments for our recursion call.

function subsequence(processedStr, unprocessedStr, arr=[]){

    if(unprocessedStr.length == 0){
        return;
    }

    // include the unprocessedStr[0] in processedStr
    // move ahead
    subsequence(processedStr + unprocessedStr[0],unprocessedStr.substring(1),arr);
    arr.push(processedStr + unprocessedStr[0]);

    // ignore the unprocessedStr[0], send processedStr as is forward
    subsequence(processedStr,unprocessedStr.substring(1),arr);

    return arr;
}

ans = subsequence("","abc");
console.log(ans);

Complexity Analysis

Time complexity - O(n*2^n)
n -> number of elements
2^n -> no of subsets for n elements

Space complexity - O(n*2^n)
n -> space taken by the subset
2^n -> number of subsets