问题描述
对于一个DNA序列(由字符 A、T、C、G 组成的字符串),找到所有可能旋转(循环移动字符串)的结果中,字典序最小的序列。
代码概述
java复制代码public class Main {
public static String solution(String dna_sequence) {
String minDNA = dna_sequence;
String doubleDNA = dna_sequence + dna_sequence;
int dnaLen = dna_sequence.length();
for (int i = 1; i < dna_sequence.length(); i++) {
String tempDNA = doubleDNA.substring(i, i + dnaLen);
if (minDNA.compareTo(tempDNA) > 0) {
minDNA = tempDNA;
}
}
return minDNA;
}
public static void main(String[] args) {
// 运行测试用例
System.out.println(solution("ATCA").equals("AATC")); // true
System.out.println(solution("CGAGTC").equals("AGTCCG")); // true
System.out.println(
solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG").equals("AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG")); // true
}
}
代码逻辑
主函数 solution
该函数的目标是找到输入DNA序列的字典序最小旋转。
1. 初始化变量
java
复制代码
String minDNA = dna_sequence;
- 将当前最小序列初始化为原始DNA序列。
java
复制代码
String doubleDNA = dna_sequence + dna_sequence;
-
将输入DNA序列复制并拼接形成“双倍长度的DNA序列”。这使得我们可以轻松提取所有旋转序列而无需手动移动字符。
-
例如,对于输入
dna_sequence = "ATCA":
doubleDNA = "ATCAATCA"
java
复制代码
int dnaLen = dna_sequence.length();
- 保存DNA序列的长度,便于提取子字符串。
2. 遍历所有可能旋转
java复制代码for (int i = 1; i < dna_sequence.length(); i++) {
String tempDNA = doubleDNA.substring(i, i + dnaLen);
- 使用
substring提取从第i个字符开始长度为dnaLen的子串。 - 每次循环提取一个可能的旋转序列。
3. 比较更新最小值
java复制代码if (minDNA.compareTo(tempDNA) > 0) {
minDNA = tempDNA;
}
- 使用
compareTo比较当前旋转序列tempDNA与当前最小序列minDNA的字典序。 - 如果
tempDNA小于minDNA,则更新minDNA。
4. 返回结果
java
复制代码
return minDNA;
- 返回最终的字典序最小旋转。
测试用例
在 main 函数中,我们通过几个测试用例验证代码的正确性。
java
复制代码
System.out.println(solution("ATCA").equals("AATC")); // true
- 输入
"ATCA"的所有旋转为:"ATCA","TCAA","CAAT","AATC" - 字典序最小的是
"AATC"。
java
复制代码
System.out.println(solution("CGAGTC").equals("AGTCCG")); // true
- 输入
"CGAGTC"的所有旋转为:"CGAGTC","GAGTCC","AGTCCG","GTCCGA","TCCGAG","CCGAGT" - 字典序最小的是
"AGTCCG"。
复杂度分析
- 时间复杂度:
- 拼接
doubleDNA的时间复杂度为 O(n)O(n)O(n)。 - 遍历所有旋转序列并比较字典序:每次比较的复杂度为 O(n)O(n)O(n),共 n−1n - 1n−1 次循环。
- 总时间复杂度为 O(n2)O(n^2)O(n2)。
- 拼接
- 空间复杂度:
- 额外使用了一个长度为 2n2n2n 的
doubleDNA字符串和若干临时字符串。 - 空间复杂度为 O(n)O(n)O(n)。
- 额外使用了一个长度为 2n2n2n 的
总结
该代码通过双倍DNA字符串的构造巧妙地实现了对所有旋转的枚举,避免了手动移动字符的复杂性。同时通过字典序比较逐步更新最小值,最终实现了功能目标。
这种方法的核心是利用字符串的性质高效地处理旋转问题。