给定一个字符串,我想创建子字符串集的最小数量,其中:

  1. 子字符串的最大长度为x
  2. 如果两个集合不同,并且一个集合中的子字符串可以由另一个集合中较小的子字符串组成,则可以排除第二个集合

例如,子字符串最大长度为3的子字符串"ABCDEF"将产生以下结果:

[
  ['abc','def'],
  ['ab','cde','f'],
  ['ab','cd','ef'],
  ['a','bcd','ef'],
]

由于条件(2),不包括['abc','de','f'].例如,‘def’由‘de’,‘f’组成.

下面的递归allSubstring()方法不太正确,而且感觉不像是正确的方法.还有一个问题是,弦越长,速度越慢.

const allSubstrings = (input,max_len = 3) => {

    if( input.length === 1) return [[input]];

    let result = [];

    const start = input.substring(1);

    allSubstrings(start).forEach(function(subresult) {
        let tmp = subresult.slice(0);

        if( tmp[0].length < max_len ){
            tmp[0] = input.charAt(0) + tmp[0];
            result.push(tmp);
        }

        if( subresult.length > 1 ){
            if( subresult.slice(0,2).join('').length <= max_len ){
                return;
            }

            if( subresult.slice(subresult.length-2).join('').length <= max_len ){
                return;
            }
        }


        tmp = subresult.slice(0);
        tmp.unshift(input.charAt(0));

        result.push(tmp);
    });

    return result;
}

推荐答案

以下是一种使用递归的可能方法,但没有针对性能进行优化(例如,没有memoization):

function splits(s: string, maxLen: number, minInitLen: number = 1): string[][] {
  const ret: string[][] = s.length ? [] : [[]];
  for (let i = Math.min(maxLen, s.length); i >= minInitLen; i--) {
    for (const r of splits(s.slice(i), maxLen, maxLen + 1 - i)) {
      ret.push([s.slice(0, i), ...r]);
    }
  }
  return ret;
}

其思想是,splits()不仅包括要拆分的字符串s和子串的最大长度maxLen,而且还包括第一个子串的最小允许长度minInitLen.当您开始拆分字符串时,这个初始长度是1,但在递归中它可能更大.毕竟,让我们假设到目前为止,您已经将"abcdef"拆分为"a".现在需要拆分"bcdef",但下一个子字符串的长度必须为3("bcd"),因为"b"将折叠为"ab","bc"将折叠为"abc".如果到目前为止已经将其拆分成"ab"个,那么下一个子字符串的长度必须至少为2("cd""cde"),因为"c"将折叠为"abc".相关的数学运算是,如果当前子串的长度为i,则下一个子串的长度必须至少为maxLen + 1 - i.

递归的基本情况是要求您拆分空字符串.在本例中,您希望返回[[]];只有一种方法可以拆分空字符串.如果要拆分一个非空字符串,则需要迭代第一个子字符串的长度i,介于minInitLenmaxLen之间(当然,也不能超过s.length),并计算递归结果splits(s.slice(i), maxLen, maxLen + 1 - i),然后对于结果中的每组字符串,在其前面加上初始子字符串s.slice(0, i).


让我们看看它是否奏效:

console.log(splits("abcdef", 3))
// [["abc", "def"], ["ab", "cde", "f"], ["ab", "cd", "ef"], ["a", "bcd", "ef"]] 

console.log(splits("abcdefgh", 5))
// [["abcde", "fgh"], ["abcd", "efgh"], ["abc", "defgh"], ["ab", "cdefg", "h"], 
//  ["ab", "cdef", "gh"], ["a", "bcdef", "gh"]] 

它看起来不错,至少对于您的示例输入是这样的.我不确定是否存在边缘情况,或者性能是否成为大型字符串的问题(这可能在很大程度上取决于"大型"的含义).如果愿意的话,当然可以重构为使用函数式编程数组方法,而不是for个循环.但至少它起作用了.

Playground link to code

Javascript相关问答推荐

主要内部的ExtJS多个子应用程序

Vue:ref不会创建react 性属性

materialized - activeIndex返回-1

格式值未保存在redux持久切片中

Plotly热图:在矩形上zoom 后将zoom 区域居中

Reaction Native中的范围滑块

如何在箭头函数中引入or子句?

创建以键值对为有效负载的Redux Reducer时,基于键的类型检测

元素字符串长度html

无法设置RazorPay订阅API项目价格

Next.js无法从外部本地主机获取图像

自动滚动功能在当前图像左侧显示上一张图像的一部分

JavaScript -复制到剪贴板在Windows计算机上无效

为什么我不能使用其同级元素调用和更新子元素?

使用createBrowserRoutVS BrowserRouter的Reaction路由

如何在TransformControls模式下只保留箭头进行翻译?

正则表达式以确定给定文本是否不只包含邮箱字符串

React数组查找不读取变量

扩散运算符未按预期工作,引发语法错误

JavaScript -如何跳过某个字符(S)来打乱字符串中的字符