Hello Habrahabr!
This article will focus on tasks for recursion and how to solve them.

Briefly about recursion
Recursion is a fairly common phenomenon that occurs not only in the fields of science, but also in everyday life. For example, the Droste effect, the Sierpinski triangle, and so on. One of the options to see the recursion is to point the webcam at the computer monitor screen, of course, by turning it on beforehand. Thus, the camera will record the image of the computer screen, and display it on this screen, you get something like a closed loop. As a result, we will see something like a tunnel.
')
In programming, recursion is closely related to functions; more precisely, it is precisely due to functions in programming that there is such a thing as recursion or recursive function. In simple words, recursion is the definition of a part of a function (method) through itself, that is, it is a function that calls itself, directly (in its body) or indirectly (through another function).
Much has been said about recursion. Here are some good resources:
It is assumed that the reader is theoretically familiar with recursion and knows what it is. In this article we will pay more attention to the tasks on recursion.
Tasks
When studying recursion, the most effective way to understand recursion is to solve problems.
How to solve the problem of recursion?
First of all, you need to understand that recursion is a kind of bust. Generally speaking, everything that is solved iteratively can be solved recursively, that is, using the recursive function.
from the networkAny algorithm implemented in a recursive form can be rewritten in an iterative form and vice versa. The question remains whether this is necessary and how effective it will be.
To substantiate you can make such arguments.
To begin with, we can recall the definition of recursion and iteration. Recursion is a method of organizing data processing in which a program calls itself directly, or with the help of other programs. Iteration is a way of organizing data processing, in which certain actions are repeated many times without leading to recursive calls of programs.
Then we can conclude that they are mutually interchangeable, but not always with the same cost of resources and speed. For justification, you can give an example: there is a function in which there is a cycle for organizing a certain algorithm that performs a sequence of actions depending on the current value of the counter (it may not depend on it). Once there is a cycle, it means that the sequence of actions is repeated in the body - a loop iteration. You can make the operation in a separate subroutine and pass it the value of the counter, if any. Upon completion of the execution of the subroutine, we check the conditions for the execution of the cycle, and if it is correct, go to a new subroutine call, if false, terminate the execution. Since we have placed the entire contents of the cycle in the subroutine, which means that the condition for the execution of the cycle is also placed in the subroutine, and it can be obtained through returning the value of the function, the parameters passed by reference or pointer to the subroutine, and global variables. Further, it is easy to show that a call from this cycle can easily be converted from a cycle to a call, or not a call (return value or just completion of work) from the subprogram itself, guided by some conditions (those that were previously in the cycle condition). Now, if we look at our abstract program, it approximately looks like the transfer of values to a subroutine and their use, which the subroutine will change upon completion, i.e. we replaced the iterative loop with a recursive subroutine call to solve this algorithm.
The task of bringing recursion to an iterative approach is symmetrical.
Summing up, we can express such thoughts: for each approach there is a class of tasks, which is determined by the specific requirements for a specific task.
More details on this can be found
here. Just like brute-force (cycle), recursion must have a stopping condition - Basic case (otherwise, like a cycle, a recursion will work forever - infinite). This condition is the case to which the recursion is going (recursion step). At each step, the recursive function is called until the next condition triggers the basic condition and the recursion stops (or rather, returns to the last function call). The whole solution comes down to solving the base case. In the case when the recursive function is called to solve a complex task (not the base case), a number of recursive calls or steps are performed, in order to reduce the problem to a simpler one. And so on until we get a basic solution.
So the recursive function consists of
- Stop condition or Basic case
- The continuation condition or recursion step is a way to make the task more simple.
Consider this on the example of finding
factorial :
public class Solution { public static int recursion(int n) {
Here the basic condition is the condition when n = 1. Since we know that 1! = 1 and to calculate 1! we do not need anything. To calculate 2! we can use 1! 2! = 1! * 2. To calculate 3! we need 2! * 3 ... To calculate n! we need (n-1)! * n. This is the recursion step. In other words, to get the value of the factorial from the number n, it is enough to multiply by n the value of the factorial from the previous number.
The network in explaining recursion also gives the problem of finding the
Fibonacci numbers and the
Tower of HanoiLet us now consider
tasks with different levels of complexity.
Try to solve them yourself using the method described above. When deciding, try thinking recursively. What is the base case in the problem? Which recursion step or recursive condition?
Go! Problem solutions are provided in Java.
A: From 1 to nGiven a positive integer n. Print all numbers from 1 to n.
Decision public class Solution { public static String recursion(int n) {
B: A to BGiven two integers A and B (each on a separate line). Output all numbers from A to B inclusive, in ascending order, if A <B, or in descending order otherwise.
Decision public class Solution { public static String recursion(int a, int b) {
C: Ackermann functionIn computability theory, the Ackermann function A (m, n) plays an important role, defined as follows:

Two non-negative integers m and n are given, each on a separate line. Output A (m, n).
Decision public class Solution { public static int recursion(int m, int n) {
D: Exact degree of twoGiven a natural number N. Output the word YES if the number N is an exact power of two, or the word NO otherwise.
The operation of exponentiation can not be used!
Decision public class Solution { public static int recursion(double n) {
E: Sum of digitsGiven a natural number N. Calculate the sum of its numbers.
When solving this problem, it is impossible to use strings, lists, arrays (well, and cycles, of course).
Decision public class Solution { public static int recursion(int n) {
F: Numbers from right to leftGiven a natural number N. Print all its digits one by one, in reverse order, separated by spaces or new lines.
When solving this problem, it is impossible to use strings, lists, arrays (well, and cycles, of course). Only recursion and integer arithmetic is allowed.
Decision public class Solution { public static int recursion(int n) {
G: Numbers from left to rightGiven a natural number N. Print all its digits one by one, in the usual order, separated by spaces or new lines.
When solving this problem, it is impossible to use strings, lists, arrays (well, and cycles, of course). Only recursion and integer arithmetic is allowed.
Decision public class Solution { public static String recursion(int n) {
H: Checking the number for simplicityGiven a positive integer n> 1. Check whether it is simple. The program should output the word YES if the number is prime and NO, if the number is composite. The algorithm must have complexity O (logn).
Note. It is clear that the task itself is non-recursive, since checking the number n for simplicity does not boil down to checking the simplicity of smaller numbers. Therefore, we need to make another recursion parameter: a divisor of the number, and it is for this parameter that recursion is to be done.
Decision public class Solution { public static boolean recursion(int n, int i) {
I: FactorizationGiven a positive integer n> 1. Print all prime factors of this number in non-decreasing order, taking into account the multiplicity. The algorithm must have complexity O (logn).
Decision public class Solution { public static void recursion(int n, int k) {
J: PalindromeGiven a word consisting of only lowercase Latin letters. Check if the word is palindrome. Output YES or NO.
When solving this problem, it is impossible to use cycles, in solutions on python it is impossible to use slices with a step other than 1.
Decision public class Solution { public static String recursion(String s) {
Another solution
public class Solution { public static boolean recursion(String s) { char firstChar; char lastChar; int size = s.length(); String subString;
K: Print odd numbers of a sequenceGiven a sequence of natural numbers (one number per line), ending with a number 0. Output all odd numbers from this sequence, keeping their order.
In this task, you cannot use global variables and pass any parameters to the recursive function. The function receives data by reading it from the keyboard. The function does not return a value, but immediately displays the result on the screen. The main program should consist only of a call to this function.
Decision public class Solution { public static void recursion() { java.util.Scanner in = new java.util.Scanner(System.in); int n = in.nextInt();
L: Print odd-numbered sequence members.Given a sequence of natural numbers (one number per line), ending with the number 0. Output the first, third, fifth, etc. from the entered numbers. The final zero should not be displayed.
In this task, you cannot use global variables and pass any parameters to the recursive function. The function receives data by reading it from the keyboard. The function does not return a value, but immediately displays the result on the screen. The main program should consist only of a call to this function.
Decision public class Solution { public static void recursion() { java.util.Scanner in = new java.util.Scanner(System.in); int n = in.nextInt();
M: Maximum sequenceGiven a sequence of natural numbers (one number per line), ending with the number 0. Determine the highest value of the number in this sequence.
In this task, you cannot use global variables and pass any parameters to the recursive function. The function receives data by reading it from the keyboard. The function returns a single value: the maximum of the read sequence. It is guaranteed that the sequence contains at least one number (except zero).
Decision public class Solution { public static int recursion() { java.util.Scanner in = new java.util.Scanner(System.in); int n = in.nextInt();
N: Mean SequenceGiven a sequence of natural numbers (one number per line), ending with the number 0. Determine the average value of the elements of this sequence (excluding the last zero).
You cannot use global variables in this task. The function receives data by reading it from the keyboard, rather than receiving it as a parameter. In the Python program, the function returns a tuple of a pair of numbers: the number of elements in the sequence and their sum. In a C ++ program, the result is recorded in two variables, which are passed to the function by reference.
It is guaranteed that the sequence contains at least one number (except zero).
Decision public class Solution { public static void recursion(int sum, int count) { java.util.Scanner in = new java.util.Scanner(System.in); int n = in.nextInt();
O: The second maximumGiven a sequence of natural numbers (one number per line), ending with the number 0. Determine the value of the second largest element in this sequence, that is, the element that will be greatest if you delete the largest element from the sequence.
You cannot use global variables in this task. The function receives data by reading it from the keyboard, rather than receiving it as a parameter. In the Python program, the function returns the result as a tuple of several numbers, and the function does not receive any parameters at all. In a C ++ program, the result is written to variables, which are passed to the function by reference. Other parameters, except as used to return the value, the function does not receive.
It is guaranteed that the sequence contains at least two numbers (except zero).
Decision public class Solution { public static void recursion(int max1, int max2) { Scanner in = new Scanner(System.in); int n = in.nextInt();
P: The number of elements equal to the maximumGiven a sequence of natural numbers (one number per line), ending with the number 0. Determine how many elements of this sequence are equal to its largest element.
You cannot use global variables in this task. The function receives data by reading it from the keyboard, rather than receiving it as a parameter. In the Python program, the function returns the result as a tuple of several numbers, and the function does not receive any parameters at all. In a C ++ program, the result is written to variables, which are passed to the function by reference. Other parameters, except as used to return the value, the function does not receive.
It is guaranteed that the sequence contains at least one number (except zero).
Decision public class Solution { public static void recursion(int max, int count) { java.util.Scanner in = new java.util.Scanner(System.in); int n = in.nextInt();
Q: Number of unitsGiven a sequence of natural numbers (one number per line), ending with two numbers 0 in a row. Determine how many times the number 1 appears in this sequence. The numbers following two zeros must be ignored.
In this task, you cannot use global variables and parameters passed to the function. The function receives data by reading it from the keyboard, rather than receiving it as parameters.
Decision public class Solution { public static int recursion() { Scanner in = new Scanner(System.in); int n = in.nextInt();
R: Triangle sequenceGiven a monotone sequence in which every positive integer k occurs exactly k times: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, ...
Given this natural n, print the first n members of this sequence. Try to do with just one for loop.
Decision public class Solution { public static String recursion(int n) { int sum = 0; int j = 0;
S: Specified amount of numbersGiven the natural numbers k and s. Determine how many k-valued positive integers exist whose sum of digits is d. Writing a natural number can not begin with the number 0.
In this task, you can use a loop to iterate through all the numbers in a position.
Decision public class Solution { public static int recursion(int len, int sum, int k, int s) {
T: No two zerosGiven the numbers a and b. Determine how many sequences there are of a zeros and b ones in which no two zeros stand side by side.
Decision public class Solution { public static int recursion(int a, int b) {
U: Number reversalGiven the number n, the decimal notation does not contain zeros. Get the number written in the same numbers, but in the opposite order.
When solving this problem, it is impossible to use cycles, strings, lists, arrays, only recursion and integer arithmetic are allowed.
The function must return an integer that is the result of the program, it is impossible to display a number by one digit.
Update from
EivindDecision public class Solution { public static int recursion(int n, int i) { return (n==0) ? i : recursion( n/10, i*10 + n%10 ); } public static void main(String[] args) { System.out.println(recursion(158, 0)); } }
That's all. I hope the solution of problems brought you as much pleasure as I did!
The article is informative and mainly intended for people who do not have much experience with recursion.
And of course, I note that the solutions to the problems written by me may not be the most effective and easy to understand. It would be useful and interesting to see your options in the comments.
I would also be very happy for your feedback and comments.
Thank!
PS: And lastly
jokes about recursion and
jokes about recursion