青训营刷题-4

154 阅读3分钟

4.环状 DNA 序列整理

环状 DNA 又称超螺旋,即一段碱基序列呈现环状,在分析时,需要将相同序列的环状 DNA 分到相同组内,现需将环状碱基序列按照最小表示法进行排序。

一段长度为 n 的碱基序列,按照顺时针方向,碱基序列可以从任意位置起开始该序列顺序,因此长度为 n 的碱基序列有 n 种表示法。例如:长度为 6 的碱基序列 CGAGTC,有 CGAGTCGAGTCCAGTCCG 等表示法。在这些表示法中,字典序最小的称为“最小表示”。

输入一个长度为 nn <= 100)的环状碱基序列(只包含 ACGT 这 4 种碱基)的一种表示法,输出该环状碱基序列的最小表示。

样例说明

ATCA 的表示有 ATCATCAACAATAATC,最小表示(根据字典序)是AATCCGAGTC 的最小表示是 AGTCCG

输入格式

一段 DNA 碱基序列

输出格式

DNA 碱基序列的最小表示

输入样例

ATCA

输出样例

AATC

解题思路

  1. 构造倍长字符串:将输入字符串 dna_sequence 与自身拼接形成 doubled 字符串,这样可以模拟环状结构。因为我们可以从任意位置开始,因此拼接后的倍长字符串 doubled 包含了所有可能的旋转子串。

  2. 双指针法:设定两个指针 leftrightleft 指向当前字典序最小子串的起始位置,而 rightleft + 1 开始,逐一比较其他可能的旋转起始位置。

  3. 比较子串的字典序:使用 compareSubstrings 方法,对 leftright 开始的长度为 n 的子串逐字符进行比较。如果 right 指向的子串字典序更小,则更新 leftright

  4. 截取结果:遍历完所有可能的起始位置后,left 会指向字典序最小的起始位置,截取并返回该位置开始的长度为 n 的子串。

算法实现

public class Main {
    public static String solution(String dna_sequence) {
        // Step 1: 获取输入序列的长度
        int n = dna_sequence.length();
        
        // Step 2: 构造倍长字符串
        String doubled = dna_sequence + dna_sequence;
        
        // Step 3: 初始化左右指针
        int left = 0;  // 当前字典序最小子串的起始位置
        int right = 1; // 下一个起始位置,用于比较
        
        // Step 4: 使用双指针找到字典序最小的起始位置
        while (right < n) {
            if (compareSubstrings(doubled, n, left, right) == 1) {
                left = right;
            }
            right++;
        }
        
        // Step 5: 从最小字典序位置开始截取长度为 n 的子串
        return doubled.substring(left, left + n);
    }

    // 辅助方法,用于比较两个起点的字典序子串
    public static int compareSubstrings(String doubled, int n, int left, int right) {
        // 按照字典序逐个字符比较长度为 n 的子串
        for (int i = 0; i < n; i++) {
            char leftChar = doubled.charAt(left + i);
            char rightChar = doubled.charAt(right + i);

            if (leftChar < rightChar) {
                return -1; // left子串更小
            } else if (leftChar > rightChar) {
                return 1; // right子串更小
            }
        }
        return 0; // 如果所有字符相等,则子串相等
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution("ATCA").equals("AATC"));        // 输出: AATC
        System.out.println(solution("CGAGTC").equals("AGTCCG"));    // 输出: AGTCCG
        System.out.println(solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG").equals("AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG"));
    }
}