字符串算法 计算子串原理

给定一个字符串 s ,计算具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是组合在一起的。要计算重复出现的子串的次数

 

输入:'00110011'
输出:6
解释:有6个子串具有相同数量的连续 1 和 0:‘0011’,‘01’,‘1100’,‘10’,‘0011’,‘01’

 

请注意,一些重复出现的子串要计算它们出现的次数。另外,‘00110011’不是有效的子串,因为所有的 0 和 1 没有组合在一起



难度大大算法题目如何解?
算法的本质是寻找规律并实现

 

如何找到规律?
发现输入和输出的关系,寻找突破点

 

复杂的实现怎么办?
实现是程序+数据结构的结合体。程序是什么,程序就是if...else,while,for循环等等,都是程序中的一种。要用什么样的数据结构去做。总的来说就是你想做出复杂的实现,首先要对程序有一个非常本质对认识,其次要熟悉所有对数据结构。而且要知道这些数据结构应该怎么去运用。



如上面对题目,接下来如何解
1、找规律,如下。把结果向输入中套。套出来再找。 类似于初中做几何题一样,在画出辅助线之前,根本就不知道这个题目的技巧在哪,但一旦找到这个辅助线了,这个几何题基本就解出来了。
对于每一种结果,他都是输入和输出一对一的关系。满足这个要求的输入和输出都是一种关系。你把这种关系都梳理出来,你基本上就找到规律了。这是非常重要的技巧

 

图谱出来后,发现有规律,从起始位置开始找,找到一位结果向下一位,找到一位结果向下一位。也就是说他每找到一个结果,他会把从下一位开始到最终作为一个子串,作为子输入。比如说从第一位0开始,到最终到结尾,这就是一个子串。然后从第二位开始,第一位就不用管了。从第二位到结尾作为一个新的输入。这个叫做子输入。这个时候就需要用到递归了,因为这个是动态的,而且这个动态之间是有关系的。这就是递归的本质。



代码
export default (str) => {
    // 建立数据结构,堆栈,保存数据
    let r = [];
    
    // 给定任意子输入都返回第一个符合条件的子串
    let match = (str) => {
        // 找到最开始的连续的 0 或者 1
        let j = str.match(/^(0+|1+)/)[0];
        // 运用 0^1 1^1 巧妙的进行取反。0^1=1,1^1=0。repeat()用于复制,比如 ‘12’.repeat(3)='121212'。里面是要复制的次数
        let o = (j[0] ^ 1).toString().repeat(j.length);
        let reg = new RegExp(`^${j}${o}`);
        if (reg.test(str)) {
            return `${j}${o}`
        } else {
            return '';
        }
    }
    
    // 通过for循环控制程序运行的流程
    for (let i = 0, len = str.length - 1; i < len; i++) {
        let sub = match(str.slice(i));
        if (sub) {
            r.push(sub);
        }
    }

    return r;
}

 

 

总结知识点
String.prototype.slice
String.prototype.match
String.prototype.repeat
String.prototype.push
RegExp

 

posted @ 2019-11-24 16:16  wzndkj  阅读(1006)  评论(0编辑  收藏  举报