0% found this document useful (0 votes)
5 views26 pages

01 STAI2 Problems Guide

The document outlines various bioinformatics algorithms and their solutions, covering topics such as finding min/max values in a list, iterating over multi-dimensional indices, and analyzing the complexity of logarithmic functions. It includes detailed pseudocode and explanations for problems related to Fibonacci numbers, coin change algorithms, and game theory. The document serves as a comprehensive guide for understanding and implementing these algorithms effectively.

Uploaded by

Ali Kelany
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views26 pages

01 STAI2 Problems Guide

The document outlines various bioinformatics algorithms and their solutions, covering topics such as finding min/max values in a list, iterating over multi-dimensional indices, and analyzing the complexity of logarithmic functions. It includes detailed pseudocode and explanations for problems related to Fibonacci numbers, coin change algorithms, and game theory. The document serves as a comprehensive guide for understanding and implementing these algorithms effectively.

Uploaded by

Ali Kelany
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Bioinformatics Algorithms — Problems &

Solutions Guide
Chapter 2 · Chapter 4 · Chapter 9 (Lecture Slides)
Table of Contents
1. Chapter 2 — Problems & Solutions
2. Chapter 4 — Problems & Solutions
3. Chapter 9 — Lecture Summary & Worked Examples

Chapter 2 — Algorithms & Complexity


{#chapter-2}
Problem 2.1 — Min and Max in a List
Problem: Write an algorithm that, given a list of n numbers, returns the largest and smallest numbers.
Can you do it in only 3n/2 comparisons?
Solution:
The standard approach scans twice → 2(n−1) comparisons. The optimal approach processes pairs of
elements:
FIND_MIN_MAX(A, n):
if n is odd:
min = max = A[0]
start = 1
else:
if A[0] < A[1]: min = A[0]; max = A[1]
else: min = A[1]; max = A[0]
start = 2

for i = start to n−1 step 2:


if A[i] < A[i+1]:
if A[i] < min: min = A[i]
if A[i+1] > max: max = A[i+1]
else:
if A[i+1] < min: min = A[i+1]
if A[i] > max: max = A[i]

return (min, max)

Analysis:
Each pair uses exactly 3 comparisons (1 internal + 1 vs min + 1 vs max)
n/2 pairs → 3n/2 total comparisons ✓
Time complexity: O(n)

Problem 2.2 — Iterating Over Multi-Dimensional Index


Problem: Write recursive and iterative algorithms to iterate over every index from (0,0,…,0) to
(n₁,n₂,…,nₐ).
Solution — Iterative (Odometer style):
ITERATE_ITERATIVE(n[1..d]):
index[1..d] = [0, 0, ..., 0]
while True:
process(index)
pos = d
while pos >= 1:
index[pos] = index[pos] + 1
if index[pos] <= n[pos]: break
index[pos] = 0
pos = pos − 1
if pos == 0: break

Solution — Recursive:
ITERATE_RECURSIVE(n[1..d], index[1..d], dim):
if dim > d:
process(index)
return
for i = 0 to n[dim]:
index[dim] = i
ITERATE_RECURSIVE(n, index, dim + 1)

// Call as: ITERATE_RECURSIVE(n, [0..0], 1)

Problem 2.3 — Big-O/Ω/Θ of log n vs n


Problem: Is log n = O(n)? Is log n = Ω(n)? Is log n = Θ(n)?
Solution:
Relationship Answer Reason
log n = O(n) YES log n ≤ n for all n ≥ 1
log n = Ω(n) NO log n / n → 0 as n → ∞
log n = Θ(n) NO Requires both O(n) and Ω(n); Ω fails
Conclusion: log n = O(n) only — log n grows strictly slower than n.
Problem 2.4 — Find the Missing Integer
Problem: Given an unsorted list of n−1 distinct integers from range 1 to n, find the missing integer in
linear time.
Solution:
The sum of 1 to n is n(n+1)/2. Subtract the actual sum to get the missing number:
FIND_MISSING(A[1..n−1], n):
expected_sum = n × (n + 1) / 2
actual_sum = 0
for i = 1 to n−1:
actual_sum = actual_sum + A[i]
return expected_sum − actual_sum

Time complexity: O(n) — a single pass through the array.

Problem 2.5 — Space-Efficient Fibonacci


Problem: Modify FIBONACCI(n) to use O(1) space instead of O(n).
Solution:
Only the two most recent values are ever needed:
FIBONACCI_CONSTANT_SPACE(n):
if n == 0: return 0
if n == 1: return 1
prev = 0
curr = 1
for i = 2 to n:
next = prev + curr
prev = curr
curr = next
return curr

Space: O(1)
Time: O(n)

Problem 2.6 — Closed-Form Fibonacci (Binet's Formula)


Problem: Prove that Fₙ = (1/√5)(φⁿ − φ̄ⁿ) where φ = (1+√5)/2, φ̄ = (1−√5)/2.
Proof by Strong Induction:
Base cases:
F₀ = (1/√5)(1 − 1) = 0 ✓
F₁ = (1/√5)(φ − φ̄) = (1/√5)(√5) = 1 ✓
Inductive step: Assume true for all k ≤ n. Both φ and φ̄ satisfy x² = x + 1, so φ² = φ+1 and φ̄² = φ̄+1.
Fₙ₊₁ = Fₙ + Fₙ₋₁
= (1/√5)(φⁿ − φ̄
ⁿ) + (1/√5)(φⁿ⁻¹ − φ̄
ⁿ⁻¹)
= (1/√5)[φⁿ⁻¹(φ+1) − φ̄
ⁿ⁻¹(φ̄
+1)]
= (1/√5)[φⁿ⁻¹·φ² − φ̄
ⁿ⁻¹·φ̄
²] ← since φ+1 = φ²
= (1/√5)(φⁿ⁺¹ − φ̄
ⁿ⁺¹) ✓

Problem 2.7 — Fibonacci Faster than O(n)


Problem: Design an algorithm to compute the nth Fibonacci number in less than O(n) time.
Solution — Matrix Exponentiation:
Using the identity: [[1,1],[1,0]]ⁿ = [[Fₙ₊₁, Fₙ],[Fₙ, Fₙ₋₁]]
MATRIX_POWER(M, n):
if n == 1: return M
if n is even:
half = MATRIX_POWER(M, n/2)
return MATRIX_MULTIPLY(half, half)
else:
return MATRIX_MULTIPLY(M, MATRIX_POWER(M, n−1))

FAST_FIBONACCI(n):
if n == 0: return 0
M = [[1,1],[1,0]]
result = MATRIX_POWER(M, n)
return result[0][1]

Time complexity: O(log n) matrix multiplications, each O(1) for 2×2 matrices.
Problem 2.8 — Limited Lifespan Rabbit Model
Problem: Model rabbit population where rabbits die after k years. Write a recurrence and pseudocode.
Recurrence:
R(n) = R(n−1) + R(n−2) − R(n − ⌊k⌋ − 1)

(Add new births, subtract pairs dying at age ⌊k⌋+1)


LIMITED_FIBONACCI(n, k):
R[0] = 1; R[1] = 1
lifespan = floor(k) + 1
for i = 2 to n:
if i <= lifespan:
R[i] = R[i−1] + R[i−2]
else:
R[i] = R[i−1] + R[i−2] − R[i − lifespan − 1]
return R[n]

For k=2.5 and the sequence gives: 1, 1, 2, 3, 4 — growing more slowly than standard Fibonacci.

Problem 2.9 — Iterative Tower of Hanoi


Problem: Write a non-recursive algorithm for Tower of Hanoi.
Solution:
Total moves = 2ⁿ − 1. For odd n, cycle pegs [source, target, auxiliary]; for even n, [source, auxiliary, target].
ITERATIVE_HANOI(n, source, target, auxiliary):
total_moves = 2^n − 1
if n is odd:
pegOrder = [source, target, auxiliary]
else:
pegOrder = [source, auxiliary, target]

for move = 1 to total_moves:


if move mod 3 == 1:
MOVE_DISK(pegOrder[0], pegOrder[1])
elif move mod 3 == 2:
MOVE_DISK_NON_SMALLEST(pegOrder[0], pegOrder[2])
else:
MOVE_DISK_NON_SMALLEST(pegOrder[1], pegOrder[2])

Time: O(2ⁿ) — optimal, since exactly 2ⁿ−1 moves are required.

Problem 2.10 — Sum of First n Integers


Problem: Prove that Σᵢ₌₁ⁿ i = n(n+1)/2.
Proof by Induction:
Base case: n=1: LHS=1, RHS=1(2)/2=1 ✓
Inductive step: Assume Σᵢ₌₁ᵏ i = k(k+1)/2. Then:
Σᵢ₌₁ᵏ⁺¹ i = k(k+1)/2 + (k+1)
= (k+1)(k/2 + 1)
= (k+1)(k+2)/2 ✓

This is exactly the formula with n = k+1. □

Problem 2.11 — Geometric Series Proofs


Problem: Prove Σᵢ₌₁ⁿ 2ⁱ = 2ⁿ⁺¹ − 2 and Σᵢ₌₁ⁿ 2⁻ⁱ = 1 − 2⁻ⁿ.
Proof:
From the geometric series formula: Σᵢ₌₀ⁿ rⁱ = (rⁿ⁺¹−1)/(r−1)
Part 1 (r=2):
Σᵢ₌₁ⁿ 2ⁱ = 2·(2ⁿ−1)/(2−1) = 2ⁿ⁺¹ − 2 ✓

Part 2 (r=1/2):
Σᵢ₌₁ⁿ (1/2)ⁱ = (1/2)·(1−(1/2)ⁿ)/(1−1/2) = 1 − (1/2)ⁿ = 1 − 2⁻ⁿ ✓

Problem 2.12 — Fix BetterChange With a New


Denomination
Problem: BETTERCHANGE fails on {25,20,10,5,1}. Add a denomination to make it correct for all M.
Solution:
The failure occurs because 25 is not a multiple of 20. For M=40, greedy picks 25+10+5=3 coins instead of
optimal 20+20=2.
Fix: Add denomination 40 → set becomes {40,25,20,10,5,1}.
Now M=40 → 1 coin directly. The greedy algorithm never needs to "commit" to 25 when 40 is available.
Key insight: A greedy algorithm is correct for a denomination set when each denomination divides
the next larger one, or when the "greedy choice property" can be proven.

Problem 2.13 — Average Coins by UCHANGE(M)


Problem: Design an algorithm that computes the average number of coins returned by UCHANGE(M) as M
varies from 1 to 100.
AVERAGE_COINS(denominations):
total_coins = 0
for M = 1 to 100:
coins = UCHANGE(M, denominations)
total_coins = total_coins + coins
return total_coins / 100

Time: O(100 × d) = O(d) where d = number of denominations.

Problem 2.14 — Verify Correctness of BetterChange


Problem: Given arbitrary denominations, decide if BETTERCHANGE is correct.
VERIFY_BETTERCHANGE(c[1..d]):
SORT_DESC(c)
for M = 1 to c[1] × d:
greedy_count = BETTERCHANGE(M, c)
optimal_count = DP_CHANGE(M, c)
if greedy_count != optimal_count:
return FALSE
return TRUE

Test up to the LCM of denominations — if greedy fails for any M in that range, it's incorrect.

Problem 2.15 — King on a Chessboard Game


Problem: King moves right, down, or diagonally SE on 8×8 board. Two players alternate; player who
places king on lower-right wins. Who wins?
Solution:
Label positions WINNING (W) or LOSING (L) by working backwards:
L = ALL reachable positions are W (opponent always wins from there)
W = at least ONE reachable position is L
Pattern: Position (i,j) is LOSING iff i ≡ j (mod 2) — equal parity.
Position (1,1): both odd → same parity → LOSING for Player 1.
Conclusion: The SECOND player wins. After any Player 1 move, parity changes; Player 2 restores
equal parity, eventually landing on (8,8).

Problem 2.16 — Rock Splitting Game


Problem: n rocks, one pile. Players alternate splitting any pile of >1 rocks. Last player to move wins. Who
wins?
Solution:
Each split increases the total number of piles by exactly 1. Starting from 1 pile, exactly n−1 total splits
occur before all piles have size 1.
n even → n−1 is odd → Player 1 makes the last move → Player 1 wins
n odd → n−1 is even → Player 2 makes the last move → Player 2 wins

Problem 2.17 — Virus vs. Bacteria


Problem: n bacteria, 1 virus. Each minute: viruses kill 1 bacterium each and double; surviving bacteria
also double. Will viruses win?
Solution:
Let B(t) = bacteria, V(t) = viruses at time t.
V(t) = 2^t
B(t) = 2^t × (n − t)

B(t) = 0 when t = n. Yes, viruses kill all bacteria after exactly n minutes.
VIRUS_KILLS(n):
V = 1; B = n; t = 0
while B > 0:
V_next = 2 × V
B_next = 2 × (B − V)
V = V_next; B = B_next; t = t + 1
return t // returns n

Time: O(n) — exactly n iterations.

Problem 2.18 — Identifying Honest Professors


Problem: 100 professors (>50 honest). Find all honest ones with ≤198 questions ("Is X honest?" asked to
Y).
Solution — Tournament Algorithm:
Key insight: If A says B is honest AND B says A is honest → they are the same type (both honest or both
dishonest).
Phase 1 (100 questions): Pair up professors (50 pairs). Ask each pair about each other (2 × 50 = 100
questions). Discard any pair where either gives a "no" answer. Keep pairs where both say "yes" — take one
representative from each surviving pair.
Phase 2 (≤98 questions): The majority of survivors are still honest. Ask all about one candidate; majority
vote reveals truth. Classify all 100 professors.
Total: ≤ 198 questions. □
Problem 2.19 — Transform 8×8 Table to All Zeros
Problem: Operations: double all values in a row, or subtract 1 from all values in a column. Reach all zeros.
Solution:
Strategy: For each column j:
1. Find the maximum value M in that column
2. For each row i, double row i until T[i][j] reaches M (power-of-2 alignment)
3. Subtract column j exactly M times
Since all entries are natural numbers and we can always double to match a power of 2, the algorithm
terminates.
Running time: O(max_value × 8²) column operations.

Problem 2.20 — Chameleon Color Convergence


Problem: n black, m green, k brown chameleons. When two different-colored meet, both become the
third color. Can all become one color?
Solution:
Invariant: (n−m) mod 3, (m−k) mod 3, and (n−k) mod 3 are all preserved under each meeting event.
Condition for convergence: All same color is possible if and only if n ≡ m ≡ k (mod 3).
Example n=1, m=3, k=5: 1 mod 3=1, 3 mod 3=0, 5 mod 3=2. Not all equal → impossible.

Chapter 4 — Exhaustive Search {#chapter-4}


Problem 4.1 — Compute Delta(X)
Problem: Write an algorithm that, given a set X, calculates the multiset ΔX.
Definition: ΔX = {|xᵢ − xⱼ| : xᵢ, xⱼ ∈ X, i ≠ j}
COMPUTE_DELTA(X[1..n]):
delta = empty multiset
for i = 1 to n:
for j = 1 to n:
if i != j:
[Link](|X[i] − X[j]|)
return delta

// Time: O(n²)
// If X has n elements → ΔX has n(n−1) elements (ordered)

Problem 4.2 — Solve the Partial Digest Problem


Problem: Given L = {1,1,1,2,2,3,3,3,4,4,5,5,6,6,6,9,9,10,11,12,15}, find X such that ΔX = L.
Solution (using the PARTIALDGEST algorithm):
width = max(L) = 15. So X must contain {0, …, 15}.
Step max(L) Try y Δ(y, X) Valid? Action
1 15 width=15 — — X={0,15}, remove 15
2 12 y=12 {12,3} ✓ both in L X={0,12,15}, remove {12,3}
3 11 y=11 {11,1,4} ✓ X={0,11,12,15}, remove {1,4,11}
4 10 y=10 {10,1,2,5} ✓ X={0,10,11,12,15}, remove {1,2,5,10}
5 9 y=9 {9,1,2,3,6} ✓ X={0,9,10,11,12,15}, remove {1,2,3,6,9}
6 6 y=6 {6,3,4,5,6,9} ✓ X={0,6,9,10,11,12,15} — DONE
Answer: X = {0, 6, 9, 10, 11, 12, 15} (or its reflection {0, 3, 4, 5, 6, 9, 15})

Problem 4.3 — Generate All m-element Subsets


Problem: Write an algorithm that generates all m-element subsets of an n-element set.
SUBSETS(S[1..n], m):
GENERATE(S, m, 1, [])

GENERATE(S, m, start, current):


if length(current) == m:
OUTPUT(current)
return
if start > n: return

// Include S[start]
[Link](S[start])
GENERATE(S, m, start+1, current)
[Link]()

// Exclude S[start]
GENERATE(S, m, start+1, current)

Time: O(C(n,m) × m) where C(n,m) = n!/(m!(n−m)!) — optimal since every subset must be visited.

Problem 4.4 — m-element Subsets of a Multiset


Problem: Generate all m-element subsets of an n-element multiset (with repeated elements).
MULTISET_SUBSETS(S[1..n], m):
SORT(S)
GENERATE_MULTI(S, m, 1, [])

GENERATE_MULTI(S, m, start, current):


if length(current) == m:
OUTPUT(current)
return
prev = NULL
for i = start to n − (m − length(current)) + 1:
if S[i] != prev: // skip duplicates at same recursion level
[Link](S[i])
GENERATE_MULTI(S, m, i+1, current)
[Link]()
prev = S[i]

Example {1,2,2,3}, m=2: Produces {1,2}, {1,3}, {2,2}, {2,3} — 4 subsets, no duplicates.
Problem 4.5 — Homometric Sets (Proof)
Problem: Prove that U⊕V = {u+v} and U⊖V = {u−v} are homometric for any U, V.
Proof:
Two sets A and B are homometric if ΔA = ΔB (same multiset of pairwise differences).
Let a₁=u₁+v₁, a₂=u₂+v₂ ∈ U⊕V. Then a₁−a₂ = (u₁−u₂)+(v₁−v₂).
Let b₁=u₁−v₁, b₂=u₂−v₂ ∈ U⊖V. Then b₁−b₂ = (u₁−u₂)−(v₁−v₂).
The multiset {(u₁−u₂)+(v₁−v₂)} over all pairs equals the multiset {(u₁−u₂)−(v₁−v₂)} because for every (u,v)
difference pair, both +v and −v contributions appear symmetrically in ΔV.
Therefore Δ(U⊕V) = Δ(U⊖V), proving homometricity. □

Problem 4.6 — Generating Functions for Delta


Problem: Verify that ΔA(x) = A(x)·A(x⁻¹) where A(x) = Σ x^(aᵢ).
Solution:
A(x)·A(x⁻¹) = (Σᵢ x^aᵢ)(Σⱼ x^(−aⱼ)) = Σᵢ Σⱼ x^(aᵢ−aⱼ)

This is exactly the generating function of ΔA = {aᵢ−aⱼ : i≠j} — confirmed. ✓


For U⊕V and U⊖V:
Δ(U⊕V)(x) = U(x)V(x) · U(x⁻¹)V(x⁻¹) = [U(x)U(x⁻¹)][V(x)V(x⁻¹)]
Δ(U⊖V)(x) = U(x)V(x⁻¹) · U(x⁻¹)V(x) = [U(x)U(x⁻¹)][V(x⁻¹)V(x)]

They are equal → confirming homometricity. ✓

Problem 4.7 — Compact PARTIALDGEST Pseudocode


Problem: Write pseudocode for PARTIALDGEST in fewer lines.
PARTIAL_DIGEST(L):
width = max(L)
[Link](width)
X = {0, width}
PLACE(L, X)

PLACE(L, X):
if L is empty: OUTPUT(X); return
y = max(L)
if VALID(y, X, L):
[Link](y); L.remove_all(delta(y, X))
PLACE(L, X)
[Link](y); L.restore_all(delta(y, X))
y2 = width − y
if VALID(y2, X, L):
[Link](y2); L.remove_all(delta(y2, X))
PLACE(L, X)
[Link](y2); L.restore_all(delta(y2, X))

VALID(y, X, L):
for each x in X:
if |y − x| not in L: return FALSE
return TRUE

Problem 4.8 — Smallest Non-Unique Delta(X)


Problem: Find a ΔX with the smallest number of elements that could arise from more than one X.
Solution:
The smallest such example requires 4 points. All sets with 2 or 3 points produce unique ΔX (up to
reflection and shift).
Example of a homometric pair:
X₁ = {0, 1, 5, 11, 13}
X₂ = {0, 1, 8, 9, 13}
Both produce the same multiset ΔX despite being different sets. The minimum non-trivial case has 4
points with ΔX having 6 elements.

Problem 4.9 — Double Digest Problem (DDP)


Problem: Devise brute force and branch-and-bound algorithms for DDP.
Brute Force:
BRUTE_FORCE_DDP(A, B, AB):
for each permutation P_A of A:
for each permutation P_B of B:
if CONSISTENT(P_A, P_B, AB):
return (P_A, P_B)

Complexity: O((|A|!)² ) — very slow.


Branch-and-Bound Improvement:
BRANCH_BOUND_DDP(A, B, AB):
build restriction map incrementally:
for each cut site of enzyme A (left to right):
place next site at position p
compute partial double-digest fragments
if any required fragment is absent from AB:
PRUNE this branch and backtrack
else:
continue placing sites

Key: Prune whenever the partial assignment creates a fragment length not present in AB.

Problem 4.10 — Probed Partial Digest Problem (PPDP)


Problem: Design brute force and branch-and-bound algorithms for PPDP.
Setup: Probe at position 0. A = negative sites, B = positive sites. Input: {b−a : a∈A, b∈B}.
Branch-and-Bound:
EXTEND(A, B, Remaining):
if Remaining is empty: OUTPUT(A, B); return
for candidate in CANDIDATE_SITES(Remaining):
if VALID_POSITIVE(candidate, A, B, Remaining):
[Link](candidate)
new_remaining = Remaining − {b−a : a in A}
EXTEND(A, B, new_remaining)
[Link](candidate)
if VALID_NEGATIVE(candidate, A, B, Remaining):
[Link](candidate)
new_remaining = Remaining − {b−a : b in B}
EXTEND(A, B, new_remaining)
[Link](candidate)

Problem 4.11 — Complete k-ary Tree Vertex Count


Problem: Find a closed-form expression for total vertices in a complete balanced k-ary tree of height L.
Solution:
Depth Nodes
0 (root) 1
1 k
2 k²
… …
L (leaves) k^L
L k L+1 −1
Total = ∑d=0 k d =​

k−1
​ (k 
= 1)

Example: DNA search tree (k=4) of height 8:


Total = (4⁹ − 1)/3 = 262143/3 = 87,381 nodes

Problem 4.12 — String Pattern Search


Problem: Given text T and pattern s, find the first occurrence of s in T.
FIND_PATTERN(T, s):
n = length(T); m = length(s)
for i = 1 to n − m + 1:
match = TRUE
for j = 1 to m:
if T[i+j−1] != s[j]:
match = FALSE; break
if match: return i
return −1

Naive complexity: O(n × m)


Improved: KMP algorithm achieves O(n + m)

Problem 4.13 — Approximate Pattern Search (Hamming


Distance)
Problem: Find first occurrence of s' in T with Hamming distance dH(s, s') ≤ k.
APPROX_FIND(T, s, k):
n = length(T); m = length(s)
for i = 1 to n − m + 1:
hamming = 0
for j = 1 to m:
if T[i+j−1] != s[j]:
hamming = hamming + 1
if hamming > k: break // early exit pruning
if hamming <= k: return i
return −1

Complexity: O(n × m) worst case. The early break significantly improves average case.

Problem 4.14 — Count l-mer Frequencies


Problem: Count occurrences of each l-mer in a string of length n.
COUNT_LMERS(text, l):
freq = empty hash map
n = length(text)
for i = 1 to n − l + 1:
lmer = text[i .. i+l−1]
freq[lmer] = [Link](lmer, 0) + 1
return freq

Complexity: O(n × l) using hash map (O(l) per hash).


For a bacterial genome (~4×10⁶ bp) with l=6: ~4M iterations. Random strings show uniform
distribution (~n/4^l per l-mer); real genomes show significant deviation — over/under-represented
motifs are biologically significant.

Problem 4.15 — Identify ANOTHERMOTIFSEARCH


Problem: Identify which algorithm ANOTHERMOTIFSEARCH is a cousin of.
Answer: ANOTHERMOTIFSEARCH is a cousin of Exhaustive Brute-Force Motif Search.
ANOTHERMOTIFSEARCH(DNA, t, n, l):
s ← (1, 1, ..., 1)
bestMotif ← FINDINSEQ(s, 1, t, n, l)
return bestMotif

FINDINSEQ(s, currentSeq, t, n, l):


bestScore ← 0
for j ← 1 to n − l + 1:
s[currentSeq] ← j
if currentSeq != t:
s ← FINDINSEQ(s, currentSeq + 1, t, n, l)
if Score(s) > bestScore:
bestScore ← Score(s)
bestMotif ← s
return bestMotif

Aspect ANOTHERMOTIFSEARCH Standard Exhaustive


Approach Recursive DFS Iterative nested loops
Explores All (n−l+1)^t combos All (n−l+1)^t combos
Pruning None None
Result Optimal Optimal
Complexity O((n−l+1)^t × lt) O((n−l+1)^t × lt)

Problem 4.16 — Identify YETANOTHERMOTIFSEARCH


Problem: Identify which algorithm YETANOTHERMOTIFSEARCH is a cousin of.
Answer: YETANOTHERMOTIFSEARCH is a cousin of Branch-and-Bound Motif Search.
FIND(s, currentSeq, t, n, l):
i ← currentSeq
bestScore ← 0
for j ← 1 to n − l + 1:
si ← j
bestPossibleScore ← Score(s, i) + (t − i) × l // UPPER BOUND
if bestPossibleScore > bestScore: // PRUNING CHECK
if currentSeq != t:
s ← FIND(s, currentSeq + 1, t, n, l)
if Score(s) > bestScore:
bestScore ← Score(s)
bestMotif ← s
return bestMotif

Key difference from ANOTHERMOTIFSEARCH:


The bound bestPossibleScore = Score(s,i) + (t−i)×l is an upper bound on the best achievable
score from the current partial assignment. If this bound ≤ current bestScore, the entire subtree is pruned
without exploration.

Problem 4.17 — Tighter Bound for Median String B&B


Problem: Derive a tighter bound using the split of l-mer w into prefix u and suffix v.
Proof:
Split motif w of length l into prefix u (length p) and suffix v (length l−p).
For any sequence j and position i:
dH(w, s_{j,i}) = dH(u, s_{j,i}[1..p]) + dH(v, s_{j,i}[p+1..l])
Therefore:
TotalDistance(w, DNA) = Σⱼ minᵢ dH(w, s_{j,i})
≥ Σⱼ minᵢ [dH(u, s_{j,i}[1..p]) + dH(v, s_{j,i}[p+1..l])]
≥ Σⱼ [minᵢ dH(u, s_{j,i}[1..p]) + minᵢ dH(v, s_{j,i}
[p+1..l])]
= TotalDistance(u, DNA) + TotalDistance(v, DNA)

Tighter bound: If TotalDistance(u, DNA) + TotalDistance(v, DNA) > bestScore , prune the
entire subtree of l-mers beginning with u. Since TotalDistance(u) can be precomputed for all (l/2)-mers,
this prune is cheap to compute and substantially tighter than the basic bound. □

Chapter 9 — Randomized Algorithms & Motif


Finding {#chapter-9}
Summary: Key Concepts
Why Randomized Algorithms?
Motif finding is NP-hard. No fast exact algorithm is known. Randomized algorithms:
1. Make random decisions so no input consistently triggers worst-case behavior
2. Can be run many times — at least one run will almost certainly find the correct answer

The Motif Finding Pipeline


Starting positions s = (s₁,...,sₜ)

Alignment matrix (t × l)

COUNT(Motifs) — 4 × l count matrix
↓ (divide by t)
PROFILE(Motifs) — 4 × l frequency matrix

Consensus string (most frequent per column)

Score(Motifs) = Σⱼ (t − max_b COUNT[b,j])
Profile Scoring
Formula: Prob(a|P) = Π_{j=1}^{l} P[a_j, j]
Worked Example:
Profile P: Pos1 Pos2 Pos3 Pos4 Pos5 Pos6
A: 1/2 7/8 3/8 0 1/8 0
C: 1/8 0 1/2 5/8 3/8 0
T: 1/8 1/8 0 0 1/4 7/8
G: 1/4 0 1/8 3/8 1/4 1/8

Prob(aaacct|P) = 1/2 × 7/8 × 3/8 × 5/8 × 3/8 × 7/8 = 0.0336 ← consensus


Prob(atacag|P) = 1/2 × 1/8 × 3/8 × 5/8 × 1/8 × 1/8 = 0.0016 ← lower

Laplace's Rule of Succession (Pseudocounts)


Problem: Any zero in PROFILE makes Prob(a|P) = 0, destroying all other position information.
Fix: Add 1 to every COUNT entry before computing PROFILE.
Before pseudocounts: After adding 1:
Motifs: T A A C A: 2+1 1+1 1+1 1+1 → 3/8 2/8 2/8 2/8
G T C T C: 0+1 1+1 1+1 1+1 → 1/8 2/8 2/8 2/8
A C T A G: 1+1 1+1 1+1 0+1 → 2/8 2/8 2/8 1/8
A G G T T: 1+1 1+1 1+1 2+1 → 2/8 2/8 2/8 3/8

Denominator = t + 4 = 4 + 4 = 8

Greedy Profile Motif Search


GREEDYMOTIFSEARCH(Dna, k, t):
BestMotifs ← first k-mer from each string in Dna
for each k-mer Motif in Dna[1]:
Motif_1 ← Motif
for i = 2 to t:
Profile ← PROFILE(Motif_1, ..., Motif_{i-1}) // with pseudocounts
Motif_i ← PROFILE_MOST_PROBABLE(Dna[i], k, Profile)
Motifs ← (Motif_1, ..., Motif_t)
if SCORE(Motifs) < SCORE(BestMotifs):
BestMotifs ← Motifs
return BestMotifs

Complexity: O((n−k+1) × t × k × (n−k+1))


Limitation: Greedy early choices may be suboptimal.

Randomized Motif Search


RANDOMIZEDMOTIFSEARCH(Dna, k, t):
Motifs ← randomly select one k-mer from each string
BestMotifs ← Motifs
while True:
Profile ← PROFILE(Motifs) // with pseudocounts
Motifs ← MOTIFS(Profile, Dna) // best k-mer per string
if SCORE(Motifs) < SCORE(BestMotifs):
BestMotifs ← Motifs
else:
return BestMotifs

Run ~1000 times and return the best result across all runs.
Why it works: Random starts create statistical bias toward the true motif. Each run has a significant
probability of capturing at least one implanted motif, which pulls the profile toward the correct solution.

Gibbs Sampler
GIBBSSAMPLER(Dna, k, t, N):
Motifs ← randomly select one k-mer from each string
BestMotifs ← Motifs
for j = 1 to N:
i ← RANDOM(1, t) // remove one random sequence
Profile ← PROFILE(all Motifs except Motif_i) // from t−1 strings
Motif_i ← PROFILE_RANDOMLY_GENERATED(Profile, Dna[i], k)
// ^ sample from distribution, NOT take maximum
if SCORE(Motifs) < SCORE(BestMotifs):
BestMotifs ← Motifs
return BestMotifs

Critical difference: PROFILE_RANDOMLY_GENERATED samples from the probability distribution — it does


not always pick the maximum probability k-mer. This allows escaping local optima.

Gibbs Sampler — Full Step-by-Step Trace


Input: t=5 sequences, l=8. Starting positions: s=(7,11,9,4,1)
Seq 1 (s=7): GTAAACAA[TATTTAT]AGC
Seq 2 (s=11): AAAATTTACC[TTAGAAG]G
Seq 3 (s=9): CCGTACTGT[CAAGCGTG]G
Seq 4 (s=4): TGA[GTAAACGA]CGTCCCA
Seq 5 (s=1): [TACTTAAC]ACCCTGTCAA

Step 1: Randomly remove Sequence 2.


Step 2: Build Profile P from seqs 1, 3, 4, 5:
Pos: 1 2 3 4 5 6 7 8
A: 1/4 2/4 2/4 3/4 1/4 1/4 1/4 2/4
C: 0 1/4 1/4 0 0 2/4 0 1/4
T: 2/4 1/4 1/4 1/4 2/4 1/4 1/4 1/4
G: 1/4 0 0 0 1/4 0 3/4 0
Consensus: T A A A T C G A

Step 3: Compute Prob(each 8-mer in Seq 2 | P):


Pos 1 (AAAATTTA): 0.000732 ← highest
Pos 2 (AAATTTAC): 0.000122
Pos 8 (ACCTTAGA): 0.000183
All others: 0

Step 4: Normalize to probability distribution:


Ratios: 6 : 1 : 1.5 (divide by minimum 0.000122)
Sum: 8.5

P(pos 1) = 6/8.5 = 0.706


P(pos 2) = 1/8.5 = 0.118
P(pos 8) = 1.5/8.5 = 0.176

Step 5: Sample from distribution → most likely pos 1 → update s₂=1.


Step 6: Repeat until no improvement.

Algorithm Comparison Table


Property Greedy Randomized Gibbs Sampler
Updates per iteration All t motifs (greedy) All t motifs ONE motif (random)
Selection method Deterministic max Deterministic max Probabilistic sample
Local optima risk High Medium Lower
Speed per run Fastest Fast Slower
Reruns needed No Yes (~1000) Yes (~20 long)
Solution quality Suboptimal Good Best
Escapes bad starts No Somewhat Better

Key Formulas Quick Reference


Formula Description
Prob(a|P) = Π_{j=1}^{l} P[a_j, j] Profile probability of k-mer a
Score(Motifs) = Σⱼ (t − max_b COUNT[b,j]) Total mismatches from consensus
TotalDist(v,DNA) = Σⱼ minᵢ dH(v, s_{j,i}) Median string objective
Nodes = (k^{L+1} − 1) / (k−1) Vertices in complete k-ary tree of height L
Hanoi(n) = 2^n − 1 Moves for n-disk Tower of Hanoi
Σᵢ₌₁ⁿ i = n(n+1)/2 Sum of first n integers
Σᵢ₌₀ⁿ rⁱ = (r^{n+1}−1)/(r−1) Geometric series
dH(u,v) = |{j : u_j ≠ v_j}| Hamming distance
|ΔX| = n(n−1)/2 Number of pairwise distances for n-point set

End of Problems & Solutions Guide

You might also like