一种环状的 DNA 结构 | 豆包MarsCode AI刷题

61 阅读3分钟

问题描述

题目链接

小C正在研究一种环状的 DNA 结构,它由四种碱基ACGT构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为 n 的碱基序列可以有 n 种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。

例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCATCAACAATAATC,其中 AATC 是字典序最小的表示。

测试样例

样例1:

输入:dna_sequence = "ATCA"
输出:'AATC'

样例2:

输入:dna_sequence = "CGAGTC"
输出:'AGTCCG'

样例3:

输入:dna_sequence = "TTGAC"
输出:'ACTTG'

解决思路

  1. 理解环状结构

    • 环状结构意味着序列可以从任意位置开始读取,例如序列 ATCA 可以有以下表示:ATCATCAACAATAATC
  2. 字典序最小

    • 字典序最小意味着我们需要找到这些表示中按字母顺序排列最小的那个。
  3. 算法步骤

    • 生成所有可能的表示:对于长度为 n 的序列,可以生成 n 种不同的表示。
    • 比较字典序:比较这些表示,找到字典序最小的那个。

代码实现

    public static String solution(int n, String template, String[] titles) {
        // Please write your code here
        String res = "";
        String temp = "";
        List<String> strS = new LinkedList<>();
        for (int i = 0; i < template.length(); i++) {
            if (template.charAt(i) == '{') {
                while (template.charAt(i) != '}') {
                    i++;
                }
                if (!temp.isEmpty()) {
                    strS.add(temp);
                    temp = "";
                }
            } else {
                temp = temp + template.charAt(i);
            }
        }
        if (!temp.isEmpty()) strS.add(temp);
        List<int []> nextS = new LinkedList<>();
        for (String str : strS) {
            int[] next = new int[str.length()];
            getNext(next, str);
            nextS.add(next);
        }

        for (String title : titles) {
            int len = title.length();
            int i = 0;
            int flag = 0;
            // 对每个title 用KMP算法进行字符串的匹配
            for (int k = 0; k < nextS.size(); k++) {
                int j = -1;
                String str = strS.get(k);
                int[] next = nextS.get(k);
                // 如果模版的最后一部分不是大括号,意味着模版与title的最后一部分一定要匹配,因此直接跳到最后一部分的匹配
                if (k == nextS.size() - 1 && template.charAt(template.length() - 1) != '}') {
                    i = len - str.length();
                }
                for ( ; i < len; i++) {
                    while (j >= 0 && str.charAt(j + 1) != title.charAt(i)) {
                        j = next[j];
                    }
                    if (title.charAt(i) == str.charAt(j + 1)) j++;
                    if (j == str.length() - 1) {
                        flag++;
                        i++;
                        break;
                    }
                }

            }
            if (flag == nextS.size()) {
                if (!res.isEmpty()) res += ",True";
                else res += "True";
            } else {
                if (!res.isEmpty()) res += ",False";
                else res += "False";
            }
        }
        return res;
    }

    public static void getNext(int[] next, String s) {
        int j  = -1;
        next[0] = j;
        for (int i = 1; i < s.length(); i++) {
            if (j >= 0 && s.charAt(i) != s.charAt(j + 1)) {
                j = next[j];
            }
            if (s.charAt(i) == s.charAt(j + 1)) j++;
            next[i] = j;
        }
    }

KMP算法的使用建议

字典序是一种字符串比较方式,按字符逐位对比,就像词典里的单词排列规则。首先比较第一个字符,若相同则继续比较下一位,直到找到不同字符决定顺序;若一个字符串是另一个的前缀,较短的排前面。例如,"apple""banana" 靠前,因为 'a''b' 小;"abc""abcd" 靠前,因为它更短。字典序适用于字符串排序、查找或构建排列,例如词典、文件名排序等。在使用时,注意它是基于字符编码比较的,因此大小写会影响顺序(如 'A' < 'a')。如果需要忽略大小写或使用自定义规则,可以通过设置比较函数实现调整。字典序在构建组合、全排列等算法中也很常用。