Lecture 5: Algorithms
August 22, 2026
๐ Last lecture we explored some automation methods such as:
if, else, else if)๐ This lecture we will shift our focus to problem solving, including:

Algorithm
An algorithm is a process / set of rules performed sequentially to solve some kind of problem.
Branching Algorithm
Branching algorithms can be visualized as a case-dependent tree structure, where each branch determines which steps the algorithm applies.

TRUE, otherwise it returns FALSE.[1] TRUE
Branching statements can be nested inside one another โ an if / else if / else block can contain another complete branching block.
{ needs a matching closing brace } โ close the inner block before the outer one.Suppose we want to classify a temperature, but โhotโ vs โcoolโ means something different depending on whether itโs a weekday or a weekend:
๐ Notice the outer branch picks weekday vs weekend, and the inner branch then checks the temperature within it โ exactly the pattern youโll need for the next exercise!
04:00
Write a function check_number that takes a single numeric input x and uses nested branching as follows:
x is positive or non-positive (zero or negative).x is positive, nest a second branch that checks whether x is even or odd, returning "positive even" or "positive odd".x is non-positive, nest a second branch that checks whether x is zero or negative, returning "zero" or "negative".Hint: the modulo operator %% is helpful for checking even / odd โ recall x %% 2 == 0 when x is even.
05:00
Consider the following lang_matrix:
[,1] [,2] [,3]
[1,] "hello" "goodbye" "friend"
[2,] "hola" "adios" "amigo"
[3,] "bonjour" "au revoir" "ami"
word_search with two character string inputs: language (english, spanish or french) and type (greeting, farewell or friend).For example:
An inefficient first attempt:
word_search <- function(a, b) {
if (a == "english" | a == "e") {
if (b == "greeting") {return(lang_matrix[1, 1])}
else if (b == "farewell") {return(lang_matrix[1, 2])}
}
else if (a == "spanish" | a == "s") {
if (b == "greeting") {return(lang_matrix[2, 1])}
else if (b == "farewell") {return(lang_matrix[2, 2])}
}
else if (a == "french" | a == "f") {
if (b == "greeting") {return(lang_matrix[3, 1])}
else if (b == "farewell") {return(lang_matrix[3, 2])}
}
else{ print("ERROR: word not found")}
}To demonstrate that there are various ways to accomplish the same task we introduce the function %in%, which tests whether a value is in a vector.
# more efficient solution using %in%
word_search <- function(language, type) {
# Name the matrix indices
dimnames(lang_matrix) <- list(c("english", "spanish", "french"),
c("greeting", "farewell", "friend"))
# Use named indices
if(
language %in% c("english", "spanish", "french") &
type %in% c("greeting", "farewell")
) {
return(lang_matrix[language, type])
} else {
print("Error: Word not found!")
}
}Branching algorithms are often excellent choices but they come with some limitations:
# Example of inefficient branching algorithm
bad_in_vector <- function(v) {
if (v[1] == 1) {print("1 is in the vector")}
else if (v[2] == 1) {print("1 is in the vector")}
else if (v[3] == 1) {print("1 is in the vector")}
else if (v[4] == 1) {print("1 is in the vector")}
else if (v[5] == 1) {print("1 is in the vector")}
else if (v[6] == 1) {print("1 is in the vector")}
else if (v[7] == 1) {print("1 is in the vector")}
else {print("1 is not in the vector")}
}Iterative Algorithm
An iterative algorithm is a process that repeats a set of instructions until a specific condition is met.
Suppose we want to count how many negative numbers appear in a vector. An iterative algorithm repeats the same check for every element:
๐ Notice the pattern: loop over every index, check a condition, then update something โ this is exactly the structure youโll use in the next exercise!
03:00
Write a function alter_entry that:
7 in the vector with 0.Below are some examples of the function output:
[1] 0 2 3 0 1
[1] 10 0 3 0 8
First we construct the surrounding function.
Then we define the for loop iterating over the indices of the input vector.
Each iteration checks whether the value at the current index is equal to 7. If it is, we replace it with 0.
which() Functionwhich() function.which() function takes a logical vector as input and returns the indices of the TRUE values.which() function could be:๐ Which function is more efficient?
In preparation for the next exercise we briefly introduce the Fibonacci sequence.
The Fibonacci sequence is a mathematical pattern occurring commonly in nature. It appears in the golden ratio, which is found in petals, seashells, and galaxy spirals.

The sequence itself is constructed by starting with the initial values \(0\) and \(1\), and every subsequent value is the sum of the previous two, i.e.
\[ x_n = x_{n-1} + x_{n-2}; \quad x_1 = 0, \quad x_2 = 1. \]
05:00
Write an iterative function fib_n that returns the \(n\)-th term of the Fibonacci sequence:
n.[1] 34
[1] 46368
We start once again by defining the function and its input.
Next we define the base cases for the first two terms of the Fibonacci sequence.
Finally we define a for loop that iteratively calculates the Fibonacci sequence up to the \(n\)-th term.
Notice that in our previous example we were required to use both branching and iteration. It is common for algorithms to require the use of several tools.
Certain tricks come up more often than others, such as:
Letโs see if we can combine these tools to solve a problem in the next exercise!
05:00
Combine some of the tools we have been studying by defining a function called last_negative that:
v.v and its index (in a 2-element vector).v does not have any negative values, returns the character string "No negative values".Below are some examples of the function output:
[1] -9 6
[1] "No negative values"
We start by defining the function and its input.
Next we define a temporary variable temp to store the last negative value and its index, or a message if no negative values are found.
Finally we define a for loop that iterates through the vector, checking for negative values and updating temp accordingly.
Sometimes we may wish to run loops inside other loops (e.g. iterating over first the rows and then the columns of a matrix), and to do so we use nested loops.
Example Nested For Loop
05:00
Write a function called two_sum that:
v and a numerical scalar target, andv that add up to the target.Assume that:
target will not be twice any value in v);target are found, return NULL; andv sum to the target.๐ See whether you can design a more efficient function using vectors!
Two very famous problems in computer science are:
R has built in functions to handle both of these problems (i.e. sort() and %in%) but to understand the challenges of these problems we take a look at two specific solutions:

In 2007, former Google CEO Eric Schmidt asked then presidential candidate Barack Obama during an interview about the best way to sort one million integers.
Obama paused for a moment and replied โI think the bubble sort would be the wrong way to go.โ

v of unsorted values.j and j+1, if v[j] > v[j+1] swap the values at those indices.v.bubble_sort <- function(v) {
n <- length(v)
for (i in 1:(n - 1)) { # iterate through n-1 loops
is_swapped <- FALSE
for (j in 1:(n - i)) { # swap values at specific indices
if (v[j] > v[j + 1]) {
temp <- v[j]
v[j] <- v[j + 1]
v[j + 1] <- temp
is_swapped <- TRUE
}
}
if (!is_swapped) { # break out of loop if fully sorted
break
}
}
return(v)
}As an example of our algorithm in action letโs define a vector of 30 numbers in a random order:
The general structure of the binary search algorithm is as follows:
v and a target value target.v equals the target, end.
target, repeat the previous step with the midpoint of the upper (lower) half of the vector.target is found.# define binary search algorithm
binary_search <- function(v, target) {
left <- 1
right <- length(v)
while (left <= right) {
mid <- floor((left + right) / 2) # check the vector midpoint
if (v[mid] == target) {
return(mid)
} else if (v[mid] < target) { # check lower
left <- mid + 1
} else {
right <- mid - 1
}
}
return(NULL)
}Recursion is another common algorithmic pattern.
Recall that we previously wrote an iterative Fibonacci algorithm.
Letโs try using recursion to create a new version of the fib_n function.
๐ The recursive Fibonacci function works exactly the same, however the implementation is much faster. The drawback is that the logic behind the implementation is less intuitive.
๐ค Today we began exploring problem solving:
๐คฉ Next class we look at: