javascriptrecursioncombinationscoin-flipping

How to return all combinations of N coin flips using recursion?


Request:

Using JavaScript, write a function that takes an integer. The integer represents the number of times a coin is flipped. Using recursive strategies only, return an array containing all possible combinations of coin flips. Use "H" to represent heads and "T" to represent tails. The order of combinations does not matter.

For example, passing in "2" would return: ["HH", "HT", "TH", "TT"]

Context:

I am relatively new to JavaScript as well as the concept of recursion. This is purely for practice and understanding, so the solution does not necessarily need to match the direction of my code below; any useful methods or other ways of thinking through this are helpful, as long as it's purely recursive (no loops).

Attempt:

My attempt at this started out simple however the "action" progressively got more convoluted as I increased the input. I believe this works for inputs of 2, 3, and 4. However, inputs of 5 or higher are missing combinations in the output. Many thanks in advance!

function coinFlips(num){
  const arr = [];
  let str = "";

  // adds base str ("H" * num)
  function loadStr(n) {
    if (n === 0) {
      arr.push(str);
      return traverseArr();
    }
    str += "H";
    loadStr(n - 1);
  }
  
  // declares start point, end point, and index to update within each str
  let start = 0;
  let end = 1;
  let i = 0;

  function traverseArr() {

    // base case
    if(i === str.length) {
      console.log(arr);
      return arr;
    }

    // updates i in base str to "T"
    // increments i
    // resets start and end
    if(end === str.length) {
      str = str.split('');
      str[i] = "T";
      str = str.join('');
      i++;
      start = i;
      end = i + 1;
      return traverseArr();
    }

    // action
    let tempStr = str.split('');
    tempStr[start] = "T";
    tempStr = tempStr.join('');
    if(!arr.includes(tempStr)){
      arr.push(tempStr);
    };
    tempStr = tempStr.split('');
    tempStr.reverse();
    tempStr = tempStr.join('');
    if(!arr.includes(tempStr)){
      arr.push(tempStr);
    };

    tempStr = str.split('');
    tempStr[end] = "T";
    tempStr = tempStr.join('');
    if(!arr.includes(tempStr)){
      arr.push(tempStr);
    };
    tempStr = tempStr.split('');
    tempStr.reverse();
    tempStr = tempStr.join('');
    if(!arr.includes(tempStr)){
      arr.push(tempStr);
    };

    tempStr = str.split('');
    tempStr[start] = "T";
    tempStr[end] = "T";
    tempStr = tempStr.join('');
    if(!arr.includes(tempStr)){
      arr.push(tempStr);
    };
    tempStr = tempStr.split('');
    tempStr.reverse();
    tempStr = tempStr.join('');
    if(!arr.includes(tempStr)){
      arr.push(tempStr);
    };

    // recursive case
    start++;
    end++;
    return traverseArr();
  }

  loadStr(num);
}

coinFlips(5);

Solution

  • function getFlips(n) {
        // Helper recursive function
        function addFlips(n, result, current) {
            if (n === 1) {
                // This is the last flip, so add the result to the array
                result.push(current + 'H');
                result.push(current + 'T');
            } else {
                // Let's say current is TTH (next combos are TTHH and TTHT)
                // Then for each of the 2 combos call add Flips again to get the next flips.
                addFlips(n - 1, result, current + 'H');
                addFlips(n - 1, result, current + 'T');
            }
        }
        // Begin with empty results
        let result = [];
        // Current starts with empty string
        addFlips(n, result, '');
        return result;
    }