题目链接
题目描述
问题描述
小C正在研究一种环状的 DNA 结构,它由四种碱基A、C、G、T构成。这种环状结构的特点是可以从任何位置开始读取序列,因此一个长度为 n 的碱基序列可以有 n 种不同的表示方式。小C的任务是从这些表示中找到字典序最小的序列,即该序列的“最小表示”。
例如:碱基序列 ATCA 从不同位置读取可能的表示有 ATCA, TCAA, CAAT, AATC,其中 AATC 是字典序最小的表示。
测试样例
样例1:
输入:
dna_sequence = "ATCA"输出:'AATC'
样例2:
输入:
dna_sequence = "CGAGTC"输出:'AGTCCG'
样例3:
输入:
dna_sequence = "TTGAC"输出:'ACTTG'
题目思路
要解决这道题,我们首先要了解什么是字典序
字典序(Lexicographic Order)是一种用于比较字符串或序列的顺序,类似于字典中单词的排列方式。在字典序中,字符串的比较是基于字符的顺序,从左到右逐个字符进行比较。以下是字典序的几个关键点:
字典序的定义
-
基本原则:
- 字符串的比较从第一个字符开始,逐个比较字符的 ASCII 值(或 Unicode 值)。
- 如果第一个字符相同,则继续比较下一个字符,直到找到不同的字符。
- 如果一个字符串是另一个字符串的前缀,则较短的字符串被认为是较小的。例如,"apple" < "applepie"。
-
字符顺序:
- 在 ASCII 编码中,字符的顺序是:空格 < '0' < '1' < ... < '9' < 'A' < 'B' < ... < 'Z' < 'a' < 'b' < ... < 'z'。这意味着大写字母的排序在小写字母之前。
怎么比较字符串呢
OK,当我们学会了什么是字典序之后,就有一个问题了,我们该如何比较两个字符串的字典序?
实际上,牛逼轰轰的c++内置了比较功能,我们只需要用 <>和==来判断就可以了
怎么解决环问题呢
题目中说,dna是一个环,我们可以通过添加断点的位置来决定这个环开始的位置,那么如何构建一个环组成的字符串就成了重中之重
巧妙的来了
我们可以将这个字符串和它本身进行拼接,从而延长一倍,这样我们可以在前半段选取断点,然后向后截取长度为一半的子串,这样就完成了环的截断问题。
接下来就很简单了,我们只需要遍历所有子串,选择最大的那个就好
题解代码
#include <iostream>
#include <string>
std::string solution(std::string dna_sequence) {
// 初始化结果字符串
std::string result = dna_sequence;
// 获取字符串长度
int n = dna_sequence.length();
// 首先将字符串扩大两倍,以处理环形结构
dna_sequence += dna_sequence;
// 遍历字符串的每个位置
for (int i = 0; i < n; i++) {
// 如果当前位置的子串比之前的子串字典序小,更新结果字符串
if(result > dna_sequence.substr(i, n))result = dna_sequence.substr(i, n);
}
// 返回结果字符串
return result;
}
int main() {
// You can add more test cases here
std::cout << (solution("ATCA") == "AATC") << std::endl;
std::cout << (solution("CGAGTC") == "AGTCCG") << std::endl;
std::cout << (solution("TCATGGAGTGCTCCTGGAGGCTGAGTCCATCTCCAGTAG") == "AGGCTGAGTCCATCTCCAGTAGTCATGGAGTGCTCCTGG") << std::endl;
return 0;
}
反思
本题的难点就是如何处理环装字符串的断点问题