使用单词表拼接长字符串的方法数

简介: 使用单词表拼接长字符串的方法数

题目

假设所有字符都是小写字母
大字符串是str
arr是去重的单词表, 每个单词都不是空字符串且可以使用任意次.
使用arr中的单词有多少种拼接str的方式. 返回方法数.

解题思路

该题为从左到右模型

步骤

基本思路就是以i位置为开头(假设前面的位置都拼接好了),有多少种拼接方法
我们遍历从i到i位置能不能拼接
i到i+1能不能拼接
i到i+2能不能拼接
....
i到N能不能拼接

    public static int ways(String str, String[] arr) {
        HashSet<String> set = new HashSet<>();
        for (String candidate : arr) {
            set.add(candidate);
        }
        return process(str, 0, set);
    }

    // 所有的可分解字符串,都已经放在了set中
    // str[i....] 能够被set中的贴纸分解的话,返回分解的方法数
    public static int process(String str, int i, HashSet<String> set) {
        if (i == str.length()) { // 没字符串需要分解了!
            return 1;
        }
        //  i....还有字符串需要分解
        int ways = 0;
        // [i ... end] 前缀串 每一个前缀串
        for (int end = i; end < str.length(); end++) {
            String pre = str.substring(i, end + 1);// [)
            if (set.contains(pre)) {
                ways += process(str, end + 1, set);
            }
        }
        return ways;
    }

方法中只有一个可变参数,这就是一个一维动态规划表

dp[i]:
str从i出发及其后面所有的字符串被set分解有几种方法
整张表都填完,0位置返回就是最终答案
复杂度O(N^3)
因为有前缀字符串的检查

优化

使用前缀树记录set的字符串,减少前缀字符串的检查代价

这个点他往下没有走向a的路了,你以后所有的前缀串都不用查了
每次查一个前缀串有没有,它就是在前缀树移动一个格子。而且如果没有路了,你可以直接返回

代码

    public static class Node {
        public boolean end;
        public Node[] nexts;

        public Node() {
            end = false;
            nexts = new Node[26];
        }
    }

    public static int ways3(String str, String[] arr) {
        if (str == null || str.length() == 0 || arr == null || arr.length == 0) {
            return 0;
        }
        Node root = new Node();
        for (String s : arr) {
            char[] chs = s.toCharArray();
            Node node = root;
            int index = 0;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i] - 'a';
                if (node.nexts[index] == null) {
                    node.nexts[index] = new Node();
                }
                node = node.nexts[index];
            }
            node.end = true;
        }
        return g(str.toCharArray(), root, 0);
    }

    // str[i...] 被分解的方法数,返回

    public static int g(char[] str, Node root, int i) {
        if (i == str.length) {
            return 1;
        }
        int ways = 0;
        Node cur = root;
        // i...end
        for (int end = i; end < str.length; end++) {
            int path = str[end] - 'a';
            if (cur.nexts[path] == null) {
                break;
            }
            cur = cur.nexts[path];
            if (cur.end) { // i...end
                ways += g(str, root, end + 1);
            }
        }
        return ways;
    }
相关文章
|
6月前
|
PHP Python
二维数组取值、拼接值成字符串
二维数组取值、拼接值成字符串
27 0
|
Java 编译器
Java字符串拼接选择的三种方式
Java字符串拼接选择的三种方式
78 0
|
3月前
|
存储 Java 数据处理
|
3月前
|
存储 算法 索引
|
6月前
|
索引 容器
06-数据容器str(字符串)-字符串的下标索引/字符串无法修改/查找字符串下标初始值/字符串的替换/字符串的分割/字符串去除前后空格/统计字符串的数量/字符串的循环遍历/对字符串进行分割
06-数据容器str(字符串)-字符串的下标索引/字符串无法修改/查找字符串下标初始值/字符串的替换/字符串的分割/字符串去除前后空格/统计字符串的数量/字符串的循环遍历/对字符串进行分割
|
6月前
字符串,每个里面包含0-N个数字,如3,8,2,编写函数,将两个这样的字符串合并,并且输出的字符串里面没有重复的数字,并从大到小排列.
字符串,每个里面包含0-N个数字,如3,8,2,编写函数,将两个这样的字符串合并,并且输出的字符串里面没有重复的数字,并从大到小排列.
35 0
|
6月前
|
Java
java字符串练习题4、统计一行字符串中所有的字符类型数量
java字符串练习题4、统计一行字符串中所有的字符类型数量
65 0
|
11月前
|
算法 测试技术 C#
|
Python
在阿里云RPA中,行数是以字符串的形式表示的,
在阿里云RPA中,行数是以字符串的形式表示的,
230 2
判断一个字符串是否全部不相同
判断一个字符串是否全部不相同
79 0
判断一个字符串是否全部不相同