#### Recursion

Recursion is a special case of reduction.

- A special case of reduction
- Reduce problem to a smaller instance of itself
- Self-reduction
- Problem instance of size n is reduced to one or more instances of size n 1 or less.
- For termination, problem instances of small size are solved by some other method as base cases.

#### Recursion in Algorithmic design

- Tail Recursion: problem reduced to a single recursive call after some work. Easy to convert algorithm into iterative or greedy algorithms. Examples: Interval scheduling, MST algorithms etc.
- Divide and Conquer: Problem reduced to multiple independent sub-problems that are solved separately. Conquer step puts together solution for bigger problem. Examples: Closest pair, median selection, quick sort.
- Backtracking: Refinement of brute force search. Build solution incrementally by invoking recursion to try all possibilities for the decision in each step.
- Dynamic Programming: problem reduced to multiple (typically) dependent or overlapping sub-problems. Use memorization to avoid re-computation of common solutions leading to iterative bottom-up algorithm

#### Backtracking

A backtracking algorithm tries to construct a solution to a computational problem incrementally, one small piece at a time. Whenever the algorithm needs to decide between multiple alternatives to the next component of the solution, it recursively evaluates every alternative and then chooses the best one.

#### State Tree

A state space tree is a tree constructed from all of the possible states of the problem as nodes, connected via state transitions from some initial state as root to some terminal state as a leaf.

#### Example 1 - The Queens problem

Problem -

- How many queens can one place on the board?
- Can one place 8 queens on the board?

Process:

Initial board with Queen 1 placement. | All the possible places that the current queen can go to. | Queen 2 placement. | Final 8-Queen problem solved in 1850 (published in 1848) |

Problem :

- How to solve problem for general n?

Intuition:

- Queens can’t be on the same row, column or diagonal
- Can have n queens max.

Search tree for 5 queens:

Each node in the state tree represents a board state. For eg. node 135 represents a board where the queens placed on column 1,3 and 5. The leaf nodes represent the final state of the board where either 5 queens are placed or it cannot proceed further.

Hence, we recursively search over an implicit tree, where we “backtrack” if certain possibilities do not work.

#### Longest Increasing Subsequence (LIS)

Definitions:

- Sequence: an ordered list $a_1$, $a_{2}$,…, $a_{n}$. Length of a sequence is number of elements in the list.
- Subsequence: $a_{i1}$ ,…, $a_{ik}$ is a subsequence of $a_{1}$,…, $a_{n}$ if 1 $\le$ $i_{1}$ < $i_{2}$ <…< $i_{k}$ $\le$ n.
- Increasing sequence: A sequence is increasing if $a_{1}$ < $a_{2}$ <…< $a_{n}$. It is non-decreasing if $a_{1}$ $\le$ $a_{2}$ $\le$ … $\le$ $a_{n}$. Similarly decreasing and non-increasing.

Problem:

- Input: A sequence of numbers $a_{1}$ , $a_{2}$,…, $a_{n}$
- Goal: Find an increasing subsequence $a_{i1}$ , $a_{i2}$ ,…, $a_{ik}$ of maximum length

- Naive solution:

`algLISNaive(A[1..n]): max = 0 for each subsequence B of A do if B is increasing and |B| > max then max = |B| Output max`

Running time: O(n$2^n$) for $2^n$ subsequences of a sequence of length n and O(n) time to check if a given sequence is increasing.

- Recursive solution for LIS(A[1..n]):
- Case 1: Does not contain A[n] in which case LIS(A[1..n]) = LIS(A[1..(n − 1)])
- Case 2: Contains A[n] in which case LIS(A[1..n]) is not so clear.
- Note: For second case we want to find a subsequence in A[1..(n − 1)] that is restricted to numbers less than A[n]. This suggests that a more general problem is LIS_smaller(A[1..n], x) which gives the longest increasing subsequence in A where each number in the sequence is less than x.

```
LIS_smaller(A[1..n], x):
if (n = 0) then return 0
m = LIS_smaller(A[1..(n − 1)], x)
if (A[n] < x) then
m = max(m, 1 + LIS_smaller(A[1..(n − 1)], A[n]))
Output m
LIS(A[1..n]):
return LIS_smaller(A[1..n], ∞)
```

Running time: O($2^n$)

#### General pattern

Backtracking algorithms are commonly used to make a sequence of decisions, with the goal of building a recursively defined structure satisfying certain constraints. Often (but not always) this goal structure is itself a sequence. For example:

- In the n-queens problem, the goal is a sequence of queen positions, one in each row, such that no two queens attack each other. For each row, the algorithm decides where to place the queen.
- In the LIS problem, the goal is a sequence of input elements that have an increasing order of value. For each input element, the algorithm decides whether to include it in the output sequence or not.

#### Additional Resources

- Textbooks
- Erickson, Jeff.
*Algorithms* - Skiena, Steven.
*The Algorithms Design Manual*- Chapter 9.1 - Backtracking
- Chapter 9.2 - Examples of sBacktracking

- Erickson, Jeff.
- Sariel’s Lecture 12