递归 求字符串所有子集

131 阅读1分钟

题目

给定一个字符串,求所有子串,包括空字符串

  • 假设给定的字符串是abc,那么以a开头的有abc、ab、ac,以b开头的有bc、b,以c开头的有c,然后是空字符串
  • 具体表现如下图所示

image.png

  • 也就是意味着每到一个字符,都有要和不要两种情况
  • 当从a开始时,需要创建要a和不要a的路径
  • 在上面基础上到b时,需要创建有b和无b的路径
  • 在上面基础上到c时,需要创建有c和无c的路径
  • 所以递归结构需要两条路,一条有当前字符往下递归,一条无当前字符往下递归
function getString(str) {
  let strArr = str.split("");
  // collectArr记录之前路径
  function getSub(strArr, i, collectArr) {
    if (i === strArr.length) {
      console.log(collectArr.join(""));
      return;
    }
    // 有当前字符
    let hasCollect = [...collectArr];
    // 没有当前字符
    let noCollect = [...collectArr];
    hasCollect[i] = strArr[i];
    getSub(strArr, i + 1, hasCollect);
    getSub(strArr, i + 1, noCollect);
  }
  getSub(strArr, 0, []);
}

getString("abc");

function getAllSubstrings(str) { 
    const substrings = new Set(); // 使用 Set 避免重复 
    function backtrack(index, current) { 
        if (index === str.length) { 
            substrings.add(current); 
            return; 
        } 
        // 选择当前字符 
        backtrack(index + 1, current + str[index]); 
        // 不选择当前字符 
        backtrack(index + 1, current); 
    } 
    backtrack(0, ""); 
    return Array.from(substrings); 
} // 示例 console.log(getAllSubstrings("abc")); // 输出: ["", "a", "b", "c", "ab", "ac", "bc", "abc"]
  • 另一种省空间的做法,通过递归回溯性改变|还原值
function getString(str) {
  let strArr = str.split("");
  // collectArr记录之前路径
  function getSub(strArr, i) {
    if (i === strArr.length) {
      console.log(strArr);
      return;
    }
    let preRes=strArr[i+1];
    getSub(strArr, i + 1);
    strArr[i+1]="";
    getSub(strArr, i + 1);
    strArr[i+1]=preRes;
  }
  getSub(strArr, 0, []);
}

getString("abc");