【算法题】网易编程题:暗黑字符串组合数

37 篇文章 0 订阅
22 篇文章 0 订阅

题目

一个字符串仅由’A’,’B’,’C’三个字符组成,若字符串中不存在’A’,’B’,’C’三个字符相邻的子串(比如ABC,BAC等),则该字符串称为暗黑字符串,否则称为单纯字符串。

求长度为L的此种字符串中有多少种是暗黑字符串?

例子:
字符串 AABBACCA,由于存在BAC子串,所以该字符串为单纯字符串。
字符串 AABBCC,由于不存在A,B,C相邻构成的子串,所以该字符串为暗黑字符串。

长度为1的字符串中,暗黑字符串总共有3种(即”A”,”B”,”C”),
长度为2的字符串中,暗黑字符串总共有9种(两个位置,每个位置有三张可能,3*3=9),
长度为3的字符串中,暗黑字符串总共有21种(三个位置,每个位置有三种可能,总共有3*3*3=27种,去除纯净字符串3!=6,结果为27-6=21种)。

解题思路

1、数学方法:推导递归公式

ndescexpression
00
1A,B,C3
2第二位都有三种3 * 3 = 9
3当两位相同(相当于只有一位)时,有三种;不同(即其余情况)时,有两种f(1) * 3 + (f(2) - f(1)) * 2 = 9 + 12 = 21
4同上f(2) * 3 + (f(3) - f(2)) * 2 = 9 * 3 + 12 * 2 = 51
nf(n) = 3*f(n-2) + 2*(f(n-1) - f(n-2)) = f(n-2) + 2*(f(n-1)

根据公式,递归解决。

代码

    public static int getNum(int n) {
        if (n == 0) {
            return 0;
        }
        if (n == 1) {
            return 3;
        }
        if (n == 2) {
            return 9;
        }
        return getNum(n - 2) + 2 * getNum(n - 1);
    }

2、遍历累加(动态规划)

只要不出现(A、B、C)即可,则每增加一位,要考虑结尾的两位情况。所以维护一个HashMap来存放n=2的情况和对应的出现次数,每加一位,累加HashMap中对应的value,最后累加HashMap中所有value值。

注:虽然有3层for循环,但是第二层和第三层循环次数是常量,由规定的abc决定,第二层是9次,第三层是3次,只是为了避免代码块重复采用的for。

代码

public static int getNum2(int n) {
        String rule = "abc";
        if (n == 0) {
            return 0;
        }
        if (n == 1) {
            return rule.length();
        }
        if (n == 2) {
            return rule.length() * rule.length();
        }

        Map<String, Integer> map = new HashMap<>();
        init(map, 1);

        for (int i = 0; i <= n - rule.length(); i++) {
            Map<String, Integer> m = new HashMap<>();
            for (String s : map.keySet()) {
                int v = map.get(s);
                for (int r = 0; r < rule.length(); r++) {
                    char c = rule.charAt(r);
                    if (isDark(s + c)) {
                        String tmp = s.substring(1) + c;
                        if (m.containsKey(tmp)) {
                            m.put(tmp, m.get(tmp) + v);
                        } else {
                            m.put(tmp, v);
                        }
                    }
                }
            }
            map = m;
        }
        int cnt = 0;
        for (Integer j : map.values()) {
            cnt += j;
        }
        return cnt;
    }

    private static void init(Map<String, Integer> m, int i) {
        m.put("aa", i);
        m.put("ab", i);
        m.put("ac", i);
        m.put("ba", i);
        m.put("bb", i);
        m.put("bc", i);
        m.put("ca", i);
        m.put("cb", i);
        m.put("cc", i);
    }

    private static boolean isDark(String s) {
        return !(s.contains("abc") || s.contains("acb") || s.contains("bac") || s.contains("bca") || s.contains("cab")
                || s.contains("cba"));
    }

3、字符串拼接

参考:http://www.cnblogs.com/warnon/p/5866544.html

代码引用

/*
     * 主要想法:长度为L的暗黑字符串可以根据最后两个字符分成两类,最后两个字符是一样的和最后两个不一样的情况。
     * 长度为L+1的暗黑字符串可以由长度为L的暗黑字符串生成。
     */
    public static long totalCount(long length) {
        if (length < 1)
            return 0;
        if (length == 1)
            return 3;
        /*
         * x1表示长度为L的字符串最后两个字符不一样的暗黑字符串个数(比如*AB,*AC等), 对于长度为2的暗黑字符串,总个数为6
         */
        long x1 = 6;
        /*
         * y1表示一个字符串最后连个字符一样的暗黑字符串个数(比如*AA,*BB等), 对于长度为2的暗黑字符串,总个数为3
         */
        long y1 = 3;
        // start from string with length 2
        length = length - 2;
        while (length-- > 0) {
            long x2 = x1 + 2 * y1;
            long y2 = x1 + y1;
            x1 = x2;
            y1 = y2;
        }
        // 长度为length的字符串中,暗黑字符串总个数
        return x1 + y1;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值