주어진 문자열의 부분집합을 사전식으로 정렬된 배열로 표현하시오.

작성 코드

(JAVA 언어로 작성된 코드 검색하여 참조. 재귀함수의 호출 스택 특성을 사용한 것으로, 아래의 그림을 참고함.)

Untitled

const powerSet = function (str) {
  // TODO: 여기에 코드를 작성합니다.
  /*
  일단은 만들어 놓고, sort() 하면 알아서 정렬되네. 그걸 바로 리턴하면 됨.
  */

  //str에서 중복된 문자는 제거하여 새 str을 만든다
  let strArr = str.split('');
  let obj = {};
  strArr.forEach(el => {
    if(obj[el] === undefined){
      obj[el] = 1;
    }
  })
  strArr = Object.keys(obj).sort() // 중복된 문자가 제거된 문자 배열. 또, 정렬 미리 해줘야 편함ㅎㅎ

  //결과를 저장할 배열 만들기
  const result = []; 

  //부분집합 만들어서 result에 push한다. 단, 같은 부분집합이 있는 경우에는 push하지 않는다. 
  //1글자: str 순회하며 str[i]를 넣는다. 단 겹치지 않는 경우만.
  //2글자: jump의 경우 다음과 같다. 

  /*
  jump에 대해서: 
  j 포함 안포함
  u 포함 안포함
  m 포함 안포함
  p 포함 안포함
  이진트리의 dfs 활용
  */
  const checked = new Array(strArr.length).fill(false); // true일때만 부분집합의 원소로 사용하겠다는 의미. 

  function dfs(index){
    if(index === strArr.length){ //base case : 인덱스가 배열의 길이와 같을 경우에는 트리의 가장 마지막까지 다 봤단 소리니까 true 여부 따라서 부분집합 만든다. 
      let str = '';
      for(let i = 0; i < strArr.length; i++){
        if(checked[i]) str += strArr[i]
      }
      result.push(str);
//솔직히 이 아래의 코드 적기는 혼자서 못할거같다. 
// 그림 그리면 코드 이해 되는데 반대로는 호출스택을 어떻게 연관지어야 할지 모르겠다. 
//01, 0, 1, '' 이런 순서로 작동함. 
    
}else{ //recursive. 트리의 끝까지 내려가면서 true 여부 체크한다. 어떻게??????
      checked[index] = true; //[true, false] //[true,true]
      dfs(index + 1); //dfs(1) //dfs(2) - ab
      checked[index] = false; //dfs(2) 에서 ab 넣고 나간 후 dfs(1) 재개 [true,false] a
      dfs(index + 1);
    }
  }
  dfs(0);

  //정렬한다
  result.sort();

  //결과 리턴한다
  return result;
};

재귀적 사고를 이용한 좀 더 쉬운 방법

근거

문제를 좀 더 작은 문제로 나눠보면, 배열의 원소 1개와 나머지 배열로 나눌 수 있다.

원소가 1개인 배열은 부분집합을 바로 쉽게 구할 수 있으니까. 이것을 base case로 두고, 나머지 배열은 재귀함수한테 처리해달라고 맡기면 되는 것이다!

예를 들어 “BC” 문자열의 부분집합을 구하려면, “B”와 “C”로 나눈다.

그런 다음, “B”의 부분집합은 [’’, “B”] 임을 쉽게 구할 수 있고, “C”의 부분집합은 “B”의 부분집합과, “B”의 부분집합을 순회하면서 “C”를 붙인 집합을 합해서 구할 수 있다.

이 과정을 아래 블로그에서 잘 설명하고 있었다.

Untitled

//좀 더 쉬운 접근 방법!!:)
const powerSet = function (str){
  //주어진 문자열을 배열로 전환 후, 중복 문자열을 제거한다.
  let arr = Array.from(str).sort();
  arr = arr.reduce((acc,cur) => {
    if(acc[acc.length - 1] === cur){
      return acc;
    }else{
      return acc.concat(cur);
    }
  },[])

  function recurse(arr){
    if(arr.length === 1){
      return ["", arr[0]];
    }else{
      return recurse(arr.slice(1)).concat(recurse(arr.slice(1)).map(el => arr[0].concat(el)));
    }
  }

  return recurse(arr).sort();
}