東京大学 新領域創成科学研究科 メディカル情報生命専攻 2024年1月実施 問題10
Author
zephyr, 祭音Myyura
Description
Suppose we have many DNA sequences. Each sequence has length , and the number of sequences is . The sequences are stored in an array , where holds the -th sequence . Assume that copying one sequence from one memory location to another takes constant time.
-
We wish to sort the sequences in alphabetical order of their left-most base. Write pseudocode of an algorithm that puts the sorted sequences into another array . The running time of the algorithm should be linearly proportional to . The sequences may contain any of the bases a, c, g, or t.
Below this point, assume that the sequences only contain bases a and c, never g or t.
-
We wish to sort the sequences in alphabetical order of their -th base , using less memory. The result should go in the array , and we are not allowed to use any other array. Write pseudocode of an algorithm to perform this sort. The running time should be linearly proportional to .
-
We wish to sort the sequences in alphabetical order of the whole sequences. Write pseudocode of an algorithm to do this sort, using the answer to question (2) as a subroutine. The worst-case running time should be linearly proportional to .
假设我们有许多DNA序列。每个序列的长度为 ,序列的数量为 。序列存储在数组 中,其中 保存第 个序列 。假设将一个序列从一个内存位置复制到另一个位置的时间是恒定的。
-
我们希望按序列最左边的碱基的字母顺序排序。编写一个算法的伪代码,将排序后的序列放入另一个数组 。算法的运行时间应与 成线性比例。序列可能包含 a、c、g 或 t 中的任意碱基。
以下假设序列仅包含碱基 a 和 c,不包含 g 或 t。
-
我们希望按序列的第 个碱基的字母顺序排序 ,使用较少的内存。结果应存放在数组 中,不允许使用任何其他数组。编写一个算法的伪代码来执行此排序。运行时间应与 成线性比例。
-
我们希望按整个序列的字母顺序对序列进行排序。编写一个算法的伪代码来执行此排序,使用问题(2)的答案作为子例程。最坏情况下的运行时间应与 成线性比例。
题目描述
有 条长度均为 的 DNA 序列,存于数组 ,其中 为第 条序列();把一整条序列从一个内存位置复制到另一个位置视为常数时间。
- 序列可含
a、c、g、t。编写伪代码,按最左端碱基的字母顺序排序,并把结果写入另一数组 ;运行时间须与 成线性关系。 - 以下仅考虑由
a、c组成的序列。对给定 ,编写按第 个碱基排序的伪代码;结果必须原地保存在 ,不得使用任何其他数组,运行时间须为 。 - 以第 2 问算法为子程序,编写按完整序列字典序排序的伪代码,并使最坏运行时间为 。
Kai
解题思路
-
第一问:针对第一个问题,我们的目标是按序列最左侧碱基的字母顺序对 DNA 序列进行排序。由于碱基的种类有限(只有a, c, g, t四种),我们可以使用计数排序(Counting Sort),这种排序算法的时间复杂度为 并且适用于这种小范围有限值排序的问题。具体做法是先统计每种碱基的数量,然后根据这些计数值确定每个序列在排序后的数组中的位置。最终将结果存储在新的数组 中。
-
第二问:在第二个问题中,我们限定了 DNA 序列仅包含碱基 a 和 c,要求我们按某个特定位置的碱基对序列进行排序,并且不得使用额外的数组。在这种情况下,可以使用荷兰国旗问题中的双指针方法。这种方法通过维护两个指针,一个从左至右移动,寻找需要交换的元素;另一个从右至左移动,同样寻找需要交换的元素。这种方法能够在 的时间复杂度内完成排序,并且不需要额外的存储空间。
-
第三问:最后一个问题要求我们按整个序列的字母顺序进行排序。此时,我们可以使用基数排序(Radix Sort),一种非比较型排序算法。该算法的关键在于从最低位(最不重要位)开始,对每一位进行排序。对于每一位的排序,我们可以使用第二问中实现的按某个位置排序的方法作为子程序。通过这种方式,我们可以保证整体排序的时间复杂度是 O(L \times N),其中 L 是序列长度,N 是序列数量。
Question 1: Sorting by the Left-Most Base
Pseudocode:
// Pseudocode for Counting Sort based on the first base
function countingSortFirstBase(A, N):
// Step 1: Initialize count array
count[1..4] = [0, 0, 0, 0] // rank 1,2,3,4 means 'a','c','g','t'
B[1..N] = new array
// Step 2: Count occurrences of each base
for i = 1 to N:
b = rank(A[i][1])
count[b] += 1
// Step 3: Calculate starting index for each base in sorted order
for j = 2 to 4:
count[j] += count[j - 1]
// Step 4: Place elements in sorted order
for i = N downto 1:
b = rank(A[i][1])
B[count[b]] = A[i]
count[b] -= 1
return B
Explanation:
- Initialize Count Array: We first initialize a count array of size 4 to count the occurrences of the bases 'a', 'c', 'g', and 't'. The array indices represent the bases:
count[0]for 'a',count[1]for 'c',count[2]for 'g', andcount[3]for 't'. - Count Occurrences: We iterate over the array and count the occurrences of each base in the left-most position of the sequences.
- Calculate Starting Indices: We compute the starting index for each base in the sorted array by accumulating the counts. This step helps determine where to place the sequences in array .
- Place Elements in Sorted Order: We iterate over the array from right to left and place each sequence in its correct position in array based on the left-most base. The count array helps track the next available position for each base.
Question 2: Sorting by the -th Base (Only 'a' and 'c')
Pseudocode:
## Pseudocode for In-Place Sorting by the j-th base using Two-Pointer Method
function sortByJthBase(A, left, right, j):
while left <= right:
if A[left][j] == 'a':
left += 1
else if A[right][j] == 'c':
right -= 1
else:
swap A[left] with A[right]
left += 1
right -= 1
return left // index of the first 'c'
Explanation:
- Initialization: We initialize two pointers,
leftstarting from the beginning andrightstarting from the end of the array . - Partitioning: The goal is to move all sequences starting with 'a' to the left and all sequences starting with 'c' to the right.
- Sorting Process:
- If
A[left][j]is 'a', we move theleftpointer to the right. - If
A[right][j]is 'c', we move therightpointer to the left. - If
A[left][j]is 'c' andA[right][j]is 'a', we swap these two sequences, move theleftpointer to the right, and therightpointer to the left.
- If
This in-place sorting ensures that all sequences in the given subarray are sorted based on the -th base without using additional memory.
Question 3: Sorting by Whole Sequence
Pseudocode:
// MSD radix sort using Question 2's partition as a subroutine
function radixSortSequences(A, left, right, j, L):
if left >= right or j > L:
return
middle = sortByJthBase(A, left, right, j)
radixSortSequences(A, left, middle - 1, j + 1, L)
radixSortSequences(A, middle, right, j + 1, L)
radixSortSequences(A, 1, N, 1, L)
Explanation:
- Radix Sort: This is a most-significant-digit radix sort. After partitioning by position , it recursively sorts the
aandcblocks by position . - Correctness: Every sequence in the first block is lexicographically smaller than every sequence in the second block; recursion orders equal-prefix sequences. Stability of the two-pointer partition is therefore unnecessary.
- Efficiency: At each of the positions, the disjoint subarrays contain sequences in total. Thus the worst-case running time is .
Knowledge
难点思路
- 基数排序的稳定性:需要确保每次排序时相同的元素顺序不变,这样最终排序结果是正确的。
- 双指针法的应用:在有限的内存情况下进行排序,尤其是排序特定的基因序列位置。
解题技巧和信息
- 在有限内存情况下排序时,双指针法非常有用。
- 基数排序对于多位数的排序非常高效,尤其在数据量较大时。
重点词汇
- Counting Sort 计数排序
- Radix Sort 基数排序
- In-Place Sort 原地排序
参考资料
- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd ed.). MIT Press. Chap. 8, 9.
- Sedgewick, R., & Wayne, K. (2011). Algorithms (4th ed.). Addison-Wesley. Chap. 2.