Challenging Programming in Python
Challenging Programming in Python
Rashid Behzadidoost
Challenging
Programming in
Python: A Problem
Solving Perspective
Challenging Programming in Python: A Problem
Solving Perspective
Habib Izadkhah · Rashid Behzadidoost
Challenging Programming
in Python: A Problem
Solving Perspective
Habib Izadkhah Rashid Behzadidoost
Department of Computer Science Department of Computer Science
University of Tabriz University of Tabriz
Tabriz, Iran Tabriz, Iran
© The Editor(s) (if applicable) and The Author(s), under exclusive license to Springer Nature
Switzerland AG 2024
This work is subject to copyright. All rights are solely and exclusively licensed by the Publisher, whether
the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse
of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and
transmission or information storage and retrieval, electronic adaptation, computer software, or by similar
or dissimilar methodology now known or hereafter developed.
The use of general descriptive names, registered names, trademarks, service marks, etc. in this publication
does not imply, even in the absence of a specific statement, that such names are exempt from the relevant
protective laws and regulations and therefore free for general use.
The publisher, the authors, and the editors are safe to assume that the advice and information in this book
are believed to be true and accurate at the date of publication. Neither the publisher nor the authors or
the editors give a warranty, expressed or implied, with respect to the material contained herein or for any
errors or omissions that may have been made. The publisher remains neutral with regard to jurisdictional
claims in published maps and institutional affiliations.
This Springer imprint is published by the registered company Springer Nature Switzerland AG
The registered company address is: Gewerbestrasse 11, 6330 Cham, Switzerland
v
vi Preface
in improving their Python programming skills. Additionally, this book is useful for
students planning to participate in programming competitions. After learning the
topics presented in this book, the learner will be capable of coding challenging
problems in Python.
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Why Python? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Non-library Based . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Enhancing Programming Skills and Creative Thinking
Through Challenging Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Prerequisite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Target Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Python Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1 How to Run a Python Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Data Types in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1 Boolean Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.2 Integer Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.3 Decimal Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.4 String Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3 Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.4 List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.4.1 List Built-in Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.4.2 List Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.5 Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.5.1 Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.6 Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.6.1 Changing List Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.7 Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.7.1 Set Built-in Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.7.2 Set Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.8 Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.8.1 Nested Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.8.2 Dictionary Built-in Functions . . . . . . . . . . . . . . . . . . . . . . . . 48
2.8.3 Dictionary Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
vii
viii Contents
2.9 Tuple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.9.1 Nested Tuple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.9.2 Tuple Built-in Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.9.3 Tuple Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.9.4 Range Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.10 Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.11 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.12 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.12.1 For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.12.2 Comprehensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.13 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.13.1 Variable Scopes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.13.2 Lambda Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.13.3 Handling the Control Flow . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.14 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
2.15 Generators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.16 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3 Math .......................................................... 77
3.1 Josephus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.2 Reaching a Point in Lattice Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.3 Brussel Choice Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.4 Inverse Collatz Conjecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.5 Counting Possible Corners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.6 Nearest S-gonal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
3.7 Finding Fulcrum Position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
3.8 Counting Sphere Pyramid Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
3.9 Grouping Coins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
3.10 Median of Triple Medians . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.11 Smallest Seven-Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.12 Postfix Evaluate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.13 Stable State in Bulgarian Solitaire . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.14 Computing the Rectangular Towers in Manhattan Skyline . . . . . . . 105
3.15 Cut Rectangular into Squares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
3.16 Eliminating Corners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
3.17 Leibniz Triangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
3.18 Collatzy Distance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
3.19 Sum of Two Squares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
3.20 Has Three Summer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
3.21 Perfect Power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
3.22 Lunar Multiplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
3.23 n-th Term of Recaman Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
3.24 Van Eck Sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.25 Non-consecutive Fibonacci Numbers . . . . . . . . . . . . . . . . . . . . . . . . . 133
3.26 Fibonacci Word . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Contents ix
xi
Chapter 1
Introduction
This chapter discusses the objectives, applications, and necessities of this book.
Most published Python books typically either cover the language’s syntax with basic
examples or focus on packages for problem-solving. However, using libraries and
simple exercises to understand Python’s structure can often be insufficient in provid-
ing developers with the necessary skills to tackle complex problems.
We believe that such approaches are inadequate for professional programmers who
are dealing with complex programs. Therefore, this book takes a different approach
by discussing problems that are not library-based (although standard libraries are
used in some programs), and presents solutions through detailed step-by-step algo-
rithms, hints, examples, and commented code. This approach is designed to equip
programmers with the necessary skills to solve more complex problems, leading to
an improvement in their overall programming abilities.
1.4 Prerequisite
This book presents and solves 90 challenges that can benefit a diverse range of people,
including computer science and engineering students, as well as anyone who wants
to master the Python language. The presented problems cover various fields, making
it suitable for a wide range of people. Moreover, this book enhances the power
of thinking and reasoning irrespective of the programming language. It can serve
as a valuable resource for teaching Python in universities or schools. Additionally,
software developers and participants in ACM or other competitions can benefit from
this book to improve their programming skills.
Chapter 2
Python Basics
This book uses Python version 3.9 and Windows 10 operating system. An integrated
development environment (IDE) is a programming environment that offers useful
features for programmers such as an editor, debugger, and code completion. The
use of an IDE simplifies Python coding. There are several popular IDEs available,
including Pycharm, Jupyter, and Spyder. The choice of IDE depends on personal
preference, as most IDEs use a Python interpreter, and their differences are mainly
in appearance and features. In this book, Spyder IDE is used for Python programming,
which requires the installation of Anaconda. Anaconda is an open-source distribution
that enables users of Windows, Linux, and other operating systems to code in Python
and R programming languages. The installation of Anaconda is a straightforward
process, like any other software, requiring only a few simple clicks. Figure 2.1 depicts
how the Anaconda must be installed. Once Anaconda is installed on Windows 10,
Spyder can be accessed by searching for ‘Spyder’ in the Windows search bar until
2
1
3 4
5
6
the Spyder icon is displayed. Clicking on the icon will open the Spyder environment,
as depicted in Fig. 2.2.
It is important to note that Spyder requires the installation of Anaconda, as men-
tioned earlier in the chapter.
Figure 2.3 depicts the Spyder environment that specifies the function of each
block, also, the F5 key can be used to run the written code.
2.1 How to Run a Python Program 7
In the real world, there are numerous objects that can exist in only two distinct states.
For example, an electronic device can be switched on or off, an individual can agree
or disagree with a particular stance, or a concept can have two opposing states. In
Python, the ‘True’ keyword signifies that the state is true, while the ‘False’ keyword
signifies that the state is false. In actuality, ‘True’ is equivalent to the numerical value
of 1, while ‘False’ is equivalent to 0.
In practice, integers are the most commonly used numeric type in real-life applica-
tions. They are widely used for counting odd and even numbers, tallying monetary
values, and similar tasks. For instance, the following code shows the addition of two
integer values:
1 x=2+3
2 print(x)
3 # Output: 5
There are several points to note regarding the code provided. Firstly, in line 1, a
variable named x is defined and assigned an integer value. Secondly, in line 2, the
print (x) statement is used to display the value stored within the variable x. Thirdly,
line 3 is a comment. In Python, comments are used to add annotations in the source
code for the purpose of improving its readability. Comments in Python are denoted
by the symbol #. It is worth noting that no explicit declaration for the variable x
is needed in Python. This is due to Python’s dynamic-typing feature, which allows
variables to be defined without specifying their type beforehand.
In the next some examples are provided in the below. Computing the remainder
of two numbers with notation % is performed, as follows:
1 x=2%3
2 print(x)
3 # Output: 2
Computing the multiplication of two numbers with notation ∗ is performed, as fol-
lows:
1 x=2*3
2 print(x)
3 # Output: 6
Computing the Division of two numbers with notation / is performed, as follows:
1 x=1/2
2 print(x)
3 # Output: 0.5
10 2 Python Basics
Computing the Division of two numbers with notation // is performed, where if the
result is decimal, their floor is taken, as follows:
1 x=1//2
2 print(x)
3 # Output: 0
Computing the power of two numbers with notation ∗∗ is performed, as follows:
1 x=2**3
2 print(x)
3 # Output: 8
Computing the minus of two numbers with notation − is performed, as follows:
1 x=2−3
2 print(x)
3 # Output: −1
In the next, the comparison operators on integers will be described. For the following
examples, the result is ‘True’ or ‘False’. For the variables of ‘a’ and ‘b’, a < b leads
to a true state if a is less than b, as follows:
1 a=4
2 b=8
3 z=a<b
4 print(z)
5 # Output: True
For the variables of ‘a’ and ‘b’, a > b leads to a true state if a is grater than b, as
follows:
1 a=4
2 b=8
3 z=a>b
4 print(z)
5 # Output: False
For the variables of ‘a’ and ‘b’, a <= b leads to a true state if a is less than or equal
to b, as follows:
1 a=4
2 b=8
3 z=b<=a
4 print(z)
5 # Output: False
For the variables of ‘a’ and ‘b’, a >= b leads to a true state if a is greater than or
equal to b, as follows:
1 a=4
2 b=8
2.2 Data Types in Python 11
3 z=b>=a
4 print(z)
5 # Output: True
For the variables of ‘a’ and ‘b’, a == b leads to a true state if a is equal to b, as
follows:
1 a=4
2 b=8
3 z=b=a
4 print(z)
5 # Output: False
For the variables of ‘a’ and ‘b’, a! = b leads to a true state if a is unequal to b, as
follows:
1 a=4
2 b=8
3 z=b!=a
4 print(z)
5 # Output: True
In the next, the logical operators on integers will be described. For the following
examples, the result is ‘True’ or ‘False’. For the variables of ‘a’ and ‘b’, a and b
leads to a true state if a and b true, as follows:
1 a=True
2 b=False
3 z= b and a
4 print(z)
5 # Output: False
1 a=True
2 b=True
3 z= b and a
4 print(z)
5 # Output: True
For the variables of ‘a’ and ‘b’, a or b leads to a true state if a or b is true, as follows:
1 a=True
2 b=False
3 z= b or a
4 print(z)
5 # Output: True
1 a=False
2 b=False
3 z= b or a
12 2 Python Basics
4 print(z)
5 # Output: False
For the variable of ‘a’, not (a) reverse the state ‘a’, as follows:
1 a=False
2 z= not(a)
3 print(z)
4 # Output: True
5 a=True
6 print(z)
7 # Output: False
In the above code, the value of variable a has changed once.
Decimal numbers are an important data type in Python, with a wide range of appli-
cations in everyday life. They are commonly used in scientific calculations, as well
as in calculations involving weights, lengths, times, and financial transactions. Dec-
imal numbers are particularly useful when precision is of utmost importance. For
instance, the multiplication of two decimal numbers in Python can be performed
using the operator ∗, as shown in the following code:
1 x=1.2*3.6
2 print(x)
3 # Output: 4.32
4 ################
5 x=0.2*4
6 print(x)
7 # Output: 0.8
Note
Note: All operators instructed for the integer numbers can be used for the
decimal numbers in Python.
In Python, strings are a fundamental data type used to represent text. They can
contain any character that Python supports and can be written using single quotes,
2.2 Data Types in Python 13
double quotes, or triple quotes. The use of single or double quotes is interchangeable,
with the only difference being that in a single-quoted string, double quotes can be
included and vice versa. Triple quotes, on the other hand, enable the creation of
strings spanning multiple lines. The following example shows how the strings in
Python are used.
1 x= ' Learning '
2 y= ' ' learning ' '
3 z= ' ' ' ' ' '
4 Learning
5 ''' '''
6 W= ' ' '
7 Learning
8 '''
In Python, an iterable object is any object that can be looped over using a loop
construct such as the for loop. In addition to strings, other iterable objects in Python
include lists, sets, tuples, dictionaries, and more.
Note
Note: Unlike strings, lists, sets, and other iterable objects, integer and decimal
types are not iterable in Python. If an attempt is made to loop over an integer
or decimal in Python, a TypeError will be raised by the Python interpreter.
String objects can be indexed, which means that individual characters within a
string can be accessed and manipulated using their position in the string. Indexing
is a common method for addressing elements within iterable objects in Python, and
is typically done using a numerical or string-based index. It is important to note
that in Python, the index of any object within an iterable is zero-based, meaning
that the first element has an index of 0, the second element has an index of 1, and
so on. The process of indexing in Python is demonstrated in Fig. 2.4. This figure
shows the string ‘university’ and its corresponding index positions highlighted in red
and orange. The red numbers represent direct indexing, where the position of each
character is indexed from left to right, starting at 0. The orange numbers represent
reverse indexing, where the position of each character is indexed from right to left,
starting at −1. In Python, for indexing objectname[n] is used, where objectname
is a variable that points to an iterable object, and n is a positive or negative integer or
14 2 Python Basics
a string. For a string object, n is a positive or negative integer. The following example
shows how the strings in Python are indexed.
1 x= ' University '
2 c=x[1]
3 print(c)
4 # output : n
5 c=x[−2]
6 print(c)
7 # t
8 '''
In addition to indexing notation, Python also provides a powerful method for address-
ing one or more elements within an iterable object, known as slicing. In Python, the
slicing notation is written as objectname[n1 : n2 : s], where objectname is a vari-
able that points to an iterable object, n1 and n2 are positive or negative integers
representing the start and end indices for slicing, and s indicates the interval between
the indices of the iterable object. The following example shows how the strings in
Python are sliced.
1 x= ' University '
2 c=x[1:3]
3 print(c)
4 # output : ni
5 c=x[2:7]
6 print(c)
7 # output : ivers
8 c=x[0:7]
9 print(c)
10 # output : Univers
11 c=x[:7]
12 print(c)
13 # output : Univers
14 c=x[4:]
15 print(c)
16 # output : ersity
17 ' ' ' ' ' 'The s t a r t and end addresses are not specified ,
18 so the whole string object is considered . ' ' ' ' ' '
19 c=x [ : : ]
20 print(c)
2.2 Data Types in Python 15
21 # output : University
22 c=x[ : : 2 ]
23 print(c)
24 # output : Uiest
25 # Reversing a string
26 c=x[::−1]
27 print(c)
28 # ytisrevinU
29 '''
In the above examples, it can be seen that if the start address is not specified,
slicing from the zero indexes is started, and if the end address is not specified, slicing
from the last index is done. Also, if the start and end addresses are not specified, the
whole string is considered. In the above examples, with x[:: 2] from the zero index
until the last index slicing is considered such that just the elements that are located in
the even indexes are selected. Additionally, to reverse a string in Python, the slicing
notation x[:: −1] can be used. This notation extracts the entire string starting from
the last index (−1) and moving towards the first index (0) with a step size of 1,
effectively reversing the order of the original string.
Note
Note: The indexing and slicing of all iterable objects in Python is the same.
In the next, the common operations in the strings can be applied with some exam-
ples being described. In all examples for the strings, stringobject is a variable that
points to a string object. For the variables of s1 and s2, notation + concat s1 and s2,
as follows:
1 s1= ' learning '
2 s2= ' data '
3 s3=s1+s2
4 print(s3)
5 # Output: learningdata
6 # defining a string that contains just a space
7 s0= ' ' ' ' ' ' ' ' ' ' ' '
8 s3=s1+s0+s2
9 print(s3)
10 # Output: learning data
16 2 Python Basics
The operator ∗ can be used to repeat a given string object multiple times. The syntax
for repeating a string is stringobject ∗ n, where stringobject is a variable that points
to a string object, and n is a positive integer indicating the number of times to repeat
the string. The following example illustrates how operator ∗ is used for the strings.
1 s1= ' learning '
2 s2=s1*3
3 # Output: learninglearninglearning
With \n, a new line in the string is generated, as follows:
1 s1= '#lea234rni ' 'ng\ nscience '
2 print(s1)
3 # Output: #lea234rning
4 science
In the above example, it can be seen that anything that Python encoding supports can
be written, and a new line is generated. With \t, a new tab in the string is generated,
as follows:
1 s1= '#lea234rni ' 'ng\ tscience '
2 print(s1)
3 # Output: #lea234rni ' 'ng science
Note
Note: A function is a block of code that performs a specific task and can
be called and executed multiple times throughout a program. Functions are a
fundamental concept in programming, allowing for the creation of modular,
reusable code that can be easily maintained and updated.
Note
Note: Built-in functions in Python are pre-defined functions that are part of the
Python language and can be executed just by referencing their name. These
functions are part of the Python Standard Library and provide a wide range of
functionality for common programming tasks, such as working with strings,
lists, and other data types.
2.2 Data Types in Python 17
Note
Note: An argument is any data that is passed to a function when it is called and
executed. This data can take many forms, such as integers, strings, lists, tuples,
dictionaries, or other objects. A parameter, on the other hand, is a variable
defined in the function that is used to receive and process the arguments passed
to the function. When calling a function in Python, one or more arguments can
be passed to the function as needed, and these arguments are then received by
the parameters of function and processed accordingly.
The string object has some built-in functions the most common ones with some
examples being described.
2.2.4.3 Count
Note
Note: If the start and end indexes are not specified, all indexes of an object are
considered.
18 2 Python Basics
2.2.4.4 Startswith
2.2.4.5 Endswith
2.2.4.6 Find
2.2.4.7 Index
Note
Note: The only difference between built-in functions of find and index is that
if the string is not found find returns −1 while index raises an error.
2.2.4.8 Encoding
Function of encoding takes two optional parameters encoding, and err or s, and
converts stringobject to an encoded sequence. Specifying the type of encod-
ing is with encoding parameter, and err or s determines if a character can not be
encoded, what should be replaced instead of the character. By default, the encod-
ing format is U T F − 8, but it can be changed to other formats. To use encode,
stringobject.encode() is used. The following example shows how encode func-
tion is used.
1 s= ' LearnScience '
2 c=s . encode()
3 print(c)
4 # b indicates i t is a byte string
5 #Output: b 'LearnScience '
6 # i f a character can not be encoded, i t will be ignored .
20 2 Python Basics
7 c=s . encode(encoding= ' ' ascii ' ' , errors= ' ' ignore ' ' )
8 print(c)
9 #Output: b 'LearnScience '
10 ' ' ' i f a character can not be encoded,
11 i t will raise a ValueError .
12 ' ' '
13 c=s . encode(encoding= ' ' ascii ' ' , errors= ' ' s t r i c t ' ' )
14 print(c)
15 #Output: b 'LearnScience '
2.2.4.9 Replace
This function replaces a given string with another string given. The r eplace takes two
string parameters of nw and pr , and optional parameter n, and stringobject.r epl-
cae( pr, nw, n), says how many times nw is replaced by pr that by default all string
that equal to pr are replaced. The following example shows how r eplace function
is used.
1 s= ' LearnScience '
2 c=s . replace ( 'n ' , ' * ' )
3 print(c)
4 #Output: Lear*Scie*ce
5 s= ' LearnScience '
6 c=s . replace ( 'n ' , ' * ' ,1)
7 print(c)
8 #Output: Lear*Science
Note
Note: The replace function doesn’t change the original string.
2.2.4.10 Strip
With stri p, any specified object is removed at the beginning or the end of string.
To use it, stringobject.stri p(char s) is used where char s is an optional parameter
that can be any string, by default, chars are space. The following example shows how
islower function is used.
1 s= ' ' ' as as as Univer sitY as s as as ' ' '
2 r=s . strip ( ' as ' )
3 print( r )
2.2 Data Types in Python 21
2.2.4.11 Join
With join, an arbitrary string object to each element of an iterable object (like string
and list) is added. To use it, stringobject. join(). The following example shows
how join function is used.
1 s1= ' learning '
2 s2= ' ** '
3 r=s2 . join (s1)
4 print( r )
5 #Output: l **e**a**r**n** i **n**g
6 s1= ' learning '
7 r= ' ' ' ' ' ' . join (s1)
8 print( r )
9 #Output: l e a r n i n g
10 s1= ' learning '
11 r= ' ' '$b ' ' ' . join (s1)
12 print( r )
13 #Output:l$be$ba$br$bn$bi$bn$bg
2.2.4.12 Split
With split, the string with a separator is splitted into a list. The stringobject.split-
(sep, m) is used to split, where sep and m are optional, and sep is a string that the
stringobject based on sep splitting is done, and m determines how many times the
split must be done. The following example shows how the split function is used. By
default, sep is a space and m is the maximum number of splitting.
1 s1= ' ' ' learning computer science ' ' '
2 r=s1 . s p l i t ()
3 print( r )
4 #Output:[ ' learning ' , 'computer ' , ' science ']
5 s1= ' ' ' learning computer science ' ' '
22 2 Python Basics
2.2.4.13 Capitalize
It capitali ze the first character (element) of a given string. The following example
shows how capitali ze function is used.
1 s= ' bulGarian '
2 r=s . capitalize ()
3 print( r )
4 #Output: BulGarian
5 s= ' Global '
6 r=s . capitalize ()
7 print( r )
8 #Output: Global
2.2.4.14 Swapcase
With swapcase, if the first character of a given string is a lower case, capitalize it,
and if the first character of a given string is a upper case, lower it. The following
example shows how swapcase function is used.
1 s= ' bulGarian '
2 r=s . swapcase()
3 print( r )
4 #Output: BulGarian
5 s= ' Global '
6 r=s . swapcase()
7 print( r )
8 #Output: global
2.2 Data Types in Python 23
2.2.4.15 Isalnum
With isalnum, if the characters of a given string are alphabet letters, numbers or
both, True is returned, else False is returned. The following example shows how
isalnum function is used.
1 s= ' bulGarian '
2 r=s . isalnum ()
3 print( r )
4 #Output: True
5 s= '#Global '
6 r=s . isalnum ()
7 print( r )
8 #Output: False
9 s= '#Global2023 '
10 r=s . isalnum ()
11 print( r )
12 #Output: True
2.2.4.16 Isnumeric
With isnumeric, if the characters of a given string are numeric, True is returned, else
False is returned. The following example shows how isnumeric function is used.
1 s= ' '
2 r=s . isnumeric ()
3 print( r )
4 s= '202220232024 '
5 r=s . isnumeric ()
6 print( r )
7 #Output: True
8 s= ' bulGarian '
9 r=s . isnumeric ()
10 print( r )
11 #Output: False
12 s= '#Global '
13 r=s . isnumeric ()
14 print( r )
15 #Output: False
16 s= '#Global2023 '
17 r=s . isnumeric ()
18 print( r )
19 #Output: False
24 2 Python Basics
2.2.4.17 Isalpha
With isalpha, if the characters of a given string are alphabet letters, True is returned,
else False is returned. The following example shows how isalpha function is used.
1 s= ' bulGarian '
2 r=s . isalpha ()
3 print( r )
4 #Output: True
5 s= '#Global '
6 r=s . isalpha ()
7 print( r )
8 #Output: False
9 s= '#Global2023 '
10 r=s . isalpha ()
11 print( r )
12 #Output: False
2.2.4.18 Islower
With islower , if the characters of a given string are in a lower case, True is returned,
else False is returned. The following example shows how islower function is used.
1 s= ' bulgarian '
2 r=s . islower ()
3 print( r )
4 #Output: True
5 s= '#global '
6 r=s . islower ()
7 print( r )
8 #Output: False
9 s= '#Global2023 '
10 r=s . islower ()
11 print( r )
12 #Output: False
2.2.4.19 Isupper
With isupper , if the characters of a given string are in an upper case, True is returned,
else False is returned. The following example shows how isupper function is used.
1 s= ' bulGarian '
2 r=s . isupper ()
2.2 Data Types in Python 25
3 print( r )
4 #Output: False
5 s= '#global '
6 r=s . isupper ()
7 print( r )
8 #Output: False
9 s= 'GLOBAL'
10 r=s . isupper ()
11 print( r )
12 #Output: True
2.2.4.20 Isspace
With isspace, if the characters of a given string are spaces, True is returned, else
False is returned. The following example shows how isspace function is used.
1 s= ' ' ' ' ' '
2 r=s . isspace ()
3 print( r )
4 #Output: True
5 s= '#global '
6 r=s . isspace ()
7 print( r )
8 #Output: False
9 s= 'world '
10 r=s . isspace ()
11 print( r )
12 #Output: False
2.2.4.21 Upper
With upper , the characters of a given string are changed to upper case. The following
example shows how upper function is used.
1 s= ' ' ' world ' ' '
2 r=s . upper ()
3 print( r )
4 #Output:WORLD
5 s= ' UniversitY '
6 r=s . upper ()
7 print( r )
8 #Output: UNIVERSITY
26 2 Python Basics
2.2.4.22 Lower
With lower , the characters of a given string are changed to lower case. The following
example shows how lower function is used.
1 s= ' ' 'worLD ' ' '
2 r=s . lower()
3 print( r )
4 #Output:world
5 s= ' UniversitY '
6 r=s . lower()
7 print( r )
8 #Output: university
9 s= 'PYTHON'
10 r=s . lower()
11 print( r )
12 #Output: python
The process of converting an object from one data type to another is known as type
conversion. Python provides built-in functions for converting between different data
types such that the type of an integer is represented by int, the decimal is represented
by f loat, and the string is represented by str . Also, the type name of any object in
Python with t ype(objectname) is taken. The following examples indicate how to
t ype function is used.
1 s= ' ' 'worLD ' ' '
2 r=type( s )
3 print( r )
4 #Output: <class ' str '>
5 s= '123 '
6 r=type( s )
7 print( r )
8 #Output:<class ' str '>
9 s=4
10 r=type( s )
11 print( r )
12 #Output: <class ' int '>
13 s=8.
14 r=type( s )
15 print( r )
16 #Output: <class ' float '>
17 s=2/4
2.2 Data Types in Python 27
18 r=type( s )
19 print( r )
20 #Output: <class ' float '>
To convert a value to another type, int (value), f loat (value), or str (value) is used,
where value is a specified object. Take a look at the following examples to see how
the conversion is made.
1 c0= ' 4.2 '
2 print(type(c0))
3 # Output: <class ' str '>
4 # Converting str to float type
5 c1=float (c0)
6 print(type(c1))
7 # Output: <class ' float '>
8 c0=4
9 print(type(c0))
10 # Output: <class ' int '>
11 # Converting int to float type
12 c1=float (c0)
13 print(type(c1))
14 # Output: <class ' float '>
15 c0=4.2
16 print(type(c0))
17 # Output: <class ' float '>
18 # Converting float to int type
19 c1=int (c0)
20 print(type(c1))
21 <class ' int '>
22 c0= 'Country '
23 '''
24 An error raises to convert
25 string l i t e r a l s to int or float
26 '''
27 c1=int (c0)
28 print(type(c1))
29 '''
30 Output: ValueError: invalid l i t e r a l
31 for int () with base 10: 'Country '
32 '''
33 c1=float (c0)
34 print(type(c1))
35 '''
36 Output: ValueError: could not
37 convert string to float : 'Country '
38 '''
28 2 Python Basics
39 c0=80
40 c1=81.9
41 c2=str (c0)
42 c3=str (c1)
43 print(type(c2))
44 print(type(c3))
45 # Output: <class ' str '>
46 # Output: <class ' str '>
Data is one of the most important entities in computer science. Data structures are
used to organize, store, and retrieve data efficiently. The choice of data structure
determines the format and organization of the stored data, and influences how the
data is stored in memory. In the following sections, we will describe some common
data structures in Python, including lists, arrays, matrices, sets, and dictionaries,
along with examples of how they can be used.
2.4 List
A linked list is a data structure where each element is linked to the next element, or
to the next and previous elements, and the elements in memory are not necessarily
stored consecutively. In Python, the list data structure is widely used and can be used
to implement other data structures such as matrices and arrays. Lists in Python are
used to store a sequence of elements, which can be of any data type supported by
Python. Lists have the following important features in Python:
1. Storing duplicate elements
There is no limit to store duplicate elements.
2. Storing heterogeneous elements Elements such as strings, integers, and strings
can be stored in a list.
3. Being sortable
A list can be sorted. For example, sort it from lower to upper, or alphabetically.
4. Being changeable
Lists are mutable data structures, which means that their content can be modified
after they are created. Once data is stored in a list, it can be changed as many
times as needed.
5. Being Iterable
A list is an iterable object that can be indexed.
In Python, lists are created using square brackets [], with the list elements separated
by commas inside the brackets. The following examples depict how the list is used.
2.4 List 29
The list object in Python provides a number of built-in functions for working with
lists, including functions for inserting, removing, counting, indexing, and more. Here
are some examples of how these functions can be used. In all examples, lst is a
variable that points to a list object, obj is any object, and iter obj is an iterable
object.
2.4.1.1 Append
With append, an object is inserted into the end of a list each time, To use it,
lst.append(obj) is used. The following examples indicate how to append func-
tion is used.
1 l s t =[2 ,3.1 , '− ' ]
2 l s t .append(77)
3 print( l s t )
4 # Output: [2,3.1, ' −' ,77]
5 lst0 =[101,102,9]
6 l s t .append( lst0 )
7 print( l s t )
8 # Output: [2 , 3.1,'−',77 [101, 102, 9]]
9 l s t .append(9.9)
10 print( l s t )
30 2 Python Basics
2.4.1.2 Extend
With extend, an iterable object is inserted into the end of a list each time. To use
it, lst.extend(iter obj) is used. With this definition, int object and float do not work
with extend function. As a solution, float and int objects must be converted to type
string and then they can work the extend function. The following examples indicate
how to extend function is used.
1 s= ' ' learning ' '
2 l s t =[]
3 l s t . extend( s )
4 # Output: [ ' l ' , ' e ' , 'a ' , ' r ' , 'n ' , ' i ' , 'n ' , 'g ']
5 s= ' ' learning ' '
In python, if a string is inserted with extend function, each character is inserted into
an index. To insert a string into an index of a list with the extend function, the string
must split as follows:
1 s= ' ' learning ' '
2 l s t =[]
3 l s t . extend( s . s p l i t ( ) )
4 # Output: [ ' ' learning ' ']
Other example are as follows:
1 lst0=[ ' theta ' ]
2 l s t =[]
3 r= ' learning '
4 l s t . extend( lst0 )
5 l s t . extend( r )
6 print( l s t )
7 # Output: [ ' theta ' , ' l ' , 'e ' , 'a ' , ' r ' , 'n ' , ' i ' , 'n ' , 'g ']
The extend() function in Python is used to add elements from an iterable object to
the end of a list. However, if a non-iterable object such as an integer or float is passed
to the extend() function, Python will raise a TypeError because the object cannot be
iterated over.
1 l s t =[]
2 l s t . extend(9)
3 # Output: TypeError: ' int ' object is not iterable
4 l s t =[]
5 l s t . extend(9.87)
6 # Output: TypeError: ' float ' object is not iterable
2.4 List 31
In the above examples, Python raises the errors, because int and float are not iterable.
Take a look at the following other examples.
1 l s t =[]
2 l s t . extend ([9])
3 # Output: [9]
4 l s t .append([9])
5 # Output: [[9]]
2.4.1.3 Insert
If an object must be inserted into a specific position, the insert function must be
used. To use it, lst.insert (ind, obj) is used, where ind is an integer that specifies
the index that the object must be inserted. The following examples indicate how to
insert function is used.
1 l s t =[1,8,9, '8 ' ,7 ,6]
2 l s t . insert(−2, ' objj ' )
3 print( l s t )
4 # Output: [1 , 8, 9, '8 ' , ' objj ' , 7, 6]
5 l s t =[1,8,9, '8 ' ,7 ,6]
6 l s t . insert (1 , ' data ' )
7 print( l s t )
8 # Output: [1 , ' data ' , 8, 9, '8 ' , ' objj ' , 7, 6]
9 l s t . insert (4 ,7)
10 print( l s t )
11 # Output: [1 , ' data ' , 8, 9, 7, '8 ' , ' objj ' , 7, 6]
As another example, consider Code 2.1. When inserting an object in position or index
zero, the new object is inserted in the index of zero and the old object is inserted in
the index or position one.
Code 2.1 Python code to insert the objects into a list in a reverse order
1 current_sublist =[]
2 current_sublist . insert (0 ,5)
3 current_sublist . insert (0 ,7)
4 current_sublist . insert (0,220)
5 '''
6 The output is:
7
8 [220, 7, 5]
9 '''
If an object is to be inserted at the same index, the previous object should be shifted
one position after the current one.
32 2 Python Basics
Note
Note: append, extend, and insert are used to put data into a list, where the
append and extend functions put the data to the end of a list each time, and
append works with objects, while extend works with iterable objects. The
insert function is used to put an object into a specified index.
2.4.1.4 Count
2.4.1.5 Index
Function of index takes three parameters obj, s and e, if lst find gobj, returns its
index in lst and else raises a ValueError, The format to use it, is lst.index(obj, s, e),
where s is the start address, and e is the end address to find the index. The following
example shows how index function is used.
1 l s t =[1, ' data ' , 8, 9, 7, 8, 7, 6]
2 c=l s t . index(8)
3 print(c)
4 # Output: 2
5 c=l s t . index(8 ,3 ,6)
6 print(c)
7 # Output: 5
2.4.1.6 Clear
To clear all content of the list object, clear function is used. No argument is sent to
clear function. The following example indicates how clear function can be used.
2.4 List 33
2.4.1.7 Remove
To remove a specific object, r emove function is used. To use it, lst.r emove(obj) is
used. If the object is not in lst, an error is raised. The following examples indicate
how r emove function is used.
1 l s t =[1, ' data ' , 8, 9, 7, '8 ' , 7, 6]
2 l s t .remove(8)
3 print( l s t )
4 # Output: [1 , ' data ' , 8, 9, 7, '8 ' , 7]
5 l s t .remove(76)
6 print( l s t )
7 # Output: ValueError: l i s t .remove(x ): x not in l i s t
2.4.1.8 Pop
To remove a specific object, pop function is used. To use it, lst. pop(ind) is used,
where ind is an optional parameter that specifies the index object is to be removed.
The default value for pop is equal to the index of the last item, and if the entered
index is not in the range index of lst, an error is raised. The following examples
indicate how pop function is used.
1 l s t =[1, ' data ' , 8, 9, 7, '8 ' , 7, 6]
2 l s t .pop(8)
3 # Output: IndexError: pop index out of range
4 l s t =[1, ' data ' , 8, 9, 7, '8 ' , 7, 6]
5 l s t .pop(3)
6 print( l s t )
7 # Output: [1 , ' data ' , 8, 7, '8 ' , 7, 6]
34 2 Python Basics
Note
Note: remove and pop are used to delete objects into a list, where remove
deletes an object by its object and pop deletes an object by its index. The
clear() function is a built-in method of the list object that is used to remove all
elements from a list, leaving it empty.
2.4.1.9 Reverse
2.4.1.10 Copy
A nested list is a list of lists; or a list/lists are into another list. The following example
creates a nested list.
1 nlst=[
2 [5.69 ,8 ,4.6] ,
3 [ 'x ' , ' a ' ,0.88] ,
4 [66, 7.7 , '8 ' ]]
All built-in functions can be applied to the nested lists. Take a look at the following
example.
1 nlst=[
2 [5.69 ,8 ,4.6] ,
3 [ 'x ' , ' a ' ,0.88] ,
4 [66, 7.7 , '8 ' ]]
5 # ind=nlst . index([66 , 7.7 , '8 '])
6 # Output: 2
In a nested list, all lists that are in other lists, have their indexes. The more nested,
the more indices must be used to access the elements of a nested list. Take a look at
the following examples.
1 nlst=[
2 [5 ,8 ,4] ,
3 [ 'x ' , ' a ' ,0.88 , ' r ' ] ,
4 [66, 7.7 ,[10 ,9 ,8] ,4] ]
5 # To access the f i s t l i s t and i t s second element
6 val=nlst [1]
7 print( val )
8 # Output: [ 'x ' , 'a ' ,0.88 , ' r ']
9 val=nlst [0][1]
10 print( val )
11 # Output: 8
12 val=nlst [2][3]
13 print( val )
14 # Output: [10, 9, 8]
15 val=nlst [2][2][1]
16 print( val )
17 # Output: 9
36 2 Python Basics
In the above examples, it can be seen that to access a nested list more than an index
must be used. With details, to access element 9 located in [66, 7.7, [10, 9, 8], 4], in
the above nested list, [2][2][1] is used, where [2] points to [66, 7.7, [10, 9, 8], 4],
[2][2] points to [10, 9, 8], and [2][2][1] points to 9.
Function of list () as input takes an optional iterable object, and converts it to a list
object, to use it, list (iter obj) is used. In a simple statement, each element of iter obj
is placed in an index of the list. Take a look at the following examples. All built-in
functions for the list that is created with [] can be applied to the list constructor.
1 l s t=l i s t ( ' learning ' )
2 print( l s t )
3 # Output: [ ' l ' , 'e ' , 'a ' , ' r ' , 'n ' , ' i ' , 'n ' , 'g ']
4 l s t=l i s t ( '1234 ' )
5 print( l s t )
6 # Output: [ '1 ' , '2 ' , '3 ' , '4 ']
2.5 Array
An array consists of data of the same type, whose elements can be accessed using its
indices. The elements in an array are stored sequentially in memory as opposed to a
list, which means that accessing the elements in the array is faster. In Python, there
is no special command to use an array, but a list is used. In other words, as the data
in the array must be of the same type, then only the data of the same type is used in
the list. In this regard, all built-in functions for the list can be applied to the arrays.
Take a look at the following examples.
1 # Creating an array of integers with the size of 6
2 arr =[1 ,4 ,5 ,7 ,9]
3 # Accessing to an element
4 print( arr =[0])
5 # Output: 1
6 # Creating an array of strings with the size of 6
7 arr=[ 'v ' , ' c ' , 'g ' , 'n ' ]
8 d=arr[0]+arr [2]
9 print(d)
10 # Output: vg
2.6 Matrix 37
2.5.1 Sort
Sort is a built-in function of the list, but sort can be applied to data of the same
type, so it applies to an array. With sor t (r ever se, key) function, the elements in
ascending or descending order are sorted. In the sort function, r ever se and key are
optional parameters such that r ever se is a binary value, and if it is False, sorts in
ascending order, else (T r ue) sorts in descending order, by default r ever se is equal to
False. The parameter of key determines the sorting criteria. The following examples
indicate how sor t function is used.
1 arr =[3,86,5,7,2,9]
2 # Sorting in ascending order
3 arr . sort ()
4 print( arr )
5 # Output: [2 , 3, 5, 7, 9, 86]
6 arr . sort ( reverse=True)
7 print( arr )
8 # Output: [86, 9, 7, 5, 3, 2]
9 arr=arr . sort ( reverse=True)
10 print( arr )
11 # Output: None
If the sorting is assigned to a variable, N one is returned, where N one means no
value and has the type of N oneT ype.
2.6 Matrix
8 88,4,32,41, respectively .
9 The third row: [66, 3 ,19 ,4] , for the third row,
10 column 0, 1,2 and 3 are
11 66, 3,19,4, respectively .
12 ' ' ' ' ' '
13 mat=[
14 [5 ,8 ,4 ,6] ,
15 [88,4,32,41] ,
16 [66, 3,19,4] ]
2.7 Set
A set object is a built-in data structure in Python that represents a collection of unique
elements. Similar to a list or tuple, a set can contain elements of different data types,
and the elements are not stored in any particular order. Some key features of sets in
Python include:
1. Non-indexable
In contrast to a list object, the set object can not be addressed by an index.
2. Unchangeable
Elements of a set can be added or removed, but not changed by another value.
3. A set cannot have duplicate elements. Sets are used for math, from a practical
point of view, sets are used to perform mathematical operations, and remove
duplicate elements. To create a set in Python, an open curly bracket ‘{’ and a
closed curly bracket ‘}’ are used with initializing value to it, or a set () is used.
The following examples indicate how a set object is used. In all examples, se is a set
object, and iter obj is an iterable object.
1 se={3,4,7,6,0,9,3,7}
2 print( se )
3 # Output: {0, 3, 4, 6, 7, 9}
4 se={7,6, ' learn ' , ' a ' , 'b ' , ' a '}
5 print( se )
6 # Output: { ' learn ' , 6, 7, 'b ' , 'a '}
Notice that with {}, a dictionary is created not a set.
Set object in Python has some built-in functions that are to be described in the next.
2.7.1.1 Add
With add function, an element to a set is added, To use it, se.add(elem) is used,
where elem can not be a list object or set object. The following examples indicate
how add function in a set is used.
1 se={3,4,7,6,0,9,3,7}
2 se .add(21)
3 # Output: {0, 3, 4, 21, 6, 7, 9}
4 se .add(43.4)
5 print( se )
6 # Output: {0, 3, 4, 21, 6, 7, 9, 43.4}
40 2 Python Basics
2.7.1.2 Update
To include a list or a set se.update(iter obj) is used. The following examples indicate
how update function in a set is used.
1 se={0, 3, 4, 21, 6, 7, 9}
2 s1={79, 'you '}
3 se . update(s1)
4 print( se )
5 # Output: {0, 3, 4, 6, 7, 9, 79, 21, 'you '}
6 l s t =[ 'nba ' ,40 , '79 ' ]
7 se . update( l s t )
8 print( se )
9 '''
10 Output: {0, 3, 4, 6, 7, 'nba ' , 9, 40, '79 ' , 79, 21, 'you '}
11 ' ' '
2.7.1.3 Clear
To clear a set clear , se.clear () is used. No argument is sent to clear function. The
following example indicates how clear function in a set can be used.
1 se={0, 3, 4, 21, 6, 7, 9}
2 se . clear ()
3 print( se )
4 # Output: set ()
2.7.1.4 Union
With union, the union of a set with an iterable object is taken, To use it, se.union
(iter obj) is used. The following examples indicate how union function in a set is
used.
2.7 Set 41
1 l s t =[600,700]
2 s t r i= 'abcd '
3 se0={0, 3, 4, 21, 6, 7, 9}
4 se1={89,890}
5 # union of se0 with se1
6 se=se0 . union(se1)
7 # Output: {0, 3, 4, 6, 7, 9, 21, 89, 890}
8 # union of se0 with se1
9 se=se1 . union(se0)
10 print( se )
11 # Output: {0, 3, 4, 6, 7, 9, 21, 89, 890}
12 # union of a set with a l i s t object
13 se=se0 . union( l s t )
14 print( se )
15 # Output: {0, 3, 4, 6, 7, 9, 21, 600, 700}
16 # union of a set with a string object
17 se=se0 . union( s t r i )
18 print( se )
19 # Output: {0, 'a ' , 3, 4, 6, 7, 9, 'b ' , 21, 'd ' , 'c '}
2.7.1.5 Intersection
1 l s t =[600,700]
2 s t r i= 'abcd '
3 se0={0, 3, 4, 21, 6, 7, 9, 600, ' c '}
4 se1={89,890}
5 # intersection of se0 with se1
6 se=se0 . intersection (se1)
7 print( se )
8 # Output: set ()
9 # intersection of se0 with se1
10 se1={89,890,21}
11 se=se1 . intersection (se0)
12 print( se )
13 # Output: {21}
14 # intersection of a set with a l i s t object
15 se=se0 . intersection ( l s t )
16 print( se )
17 # Output: {600}
18 # intersection of a set with a string object
19 se=se0 . intersection ( s t r i )
20 print( se )
21 # Output: { 'c '}
2.7.1.6 Intersection_update
2.7.1.7 Discard
With discar d, an element of a set is discarded and if the element does not exist,
no error is raised, To use it, discar d.intersection(elem) is used. The following
examples indicate how discar d function in a set is used.
1 se={0, 3, 4, 21, 6, 7, 9,600, ' c '}
2 se . discard (4)
3 print( se )
4 # Output: {0, 3, 6, 7, 9, 'c ' , 21, 600}
5 # 'qr ' does not exist in se , but no error is raised .
6 se . discard ( ' qr ' )
7 print( se )
8 # Output: {0, 3, 6, 7, 9, 'c ' , 21, 600}
2.7.1.8 Remove
With r emove, an element of a set is removed and if the element does not exist, an
error is raised, To use it, se.r emove(elem) is used. The following examples indicate
how r emove function in a set is used.
1 se={0, 3, 4, 21, 6, 7, 9, 600, ' c '}
2 se . discard (4)
3 print( se )
4 # Output: {0, 3, 6, 7, 9, 'c ' , 21, 600}
5 # 'qr ' does not exist in se , so an error is raised .
6 se . discard ( ' qr ' )
7 print( se )
8 # Output: KeyError: 'qr '
2.7.1.9 Pop
With pop, an element of a set is randomly removed and the removed item is returned.
No argument is sent to pop function. The following examples indicate how pop
function in a set is used.
1 se={0, 3, 4, 21, 6, 7, 9, 600, ' c '}
2 d=se .pop()
3 print(d)
4 # Output: 0
44 2 Python Basics
2.7.1.10 Difference
With se.di f f er ence(iter obj), the items that are se and not in iter obj are returned.
1 se0 = {0, 3, 4, 21, 6, 7, 9}
2 se1 = {7, 8, 3, 19, 4, 'word '}
3 ls1 =[7, 8, 3, 19, 4, 'word ' ]
4 se=se0 . difference ( ls1 )
5 print( se )
6 # Output: {0, 21, 6, 9}
7 se=se1 . difference (se0)
8 print( se )
9 # Output: {8, 19, 'word '}
Notice that the difference also can be applied with − operator, but it just works with
the sets, not any iterable objects. Take a look at the following examples.
1 se0 = {0, 3, 4, 21, 6, 7, 9}
2 se1 = {7, 8, 3, 19, 4, 'word '}
3 ls1 =[7, 8, 3, 19, 4, 'word ' ]
4 se=se0 − se1
5 print( se )
6 # Output: {0, 9, 21, 6}
7 se=se1 − se0
8 print( se )
9 # Output: {8, 19, 'word '}
10 se=se0 − l s t
11 print( se )
12 ' ' '
13 Output: TypeError: unsupported operand
14 type ( s ) for −: ' set ' and ' l i s t '
15 ' ' '
2.7.1.11 Copy
In the above example, it can be seen that every change to se1, also will be applied to
se2. In fact, with an assignment, a distinct copy is not to be created (like lists). To this
end, copy function is used that has no parameter. The following example indicates
how copy function can be used.
1 se1={1, ' learn ' , 8, 9, 7, '8 ' , 7, 6}
2 se2=se1 .copy()
3 se1 . discard ( ' learn ' )
4 print(se1)
5 # Output: {1, '8 ' , 6, 7, 8, 9}
6 print(se2)
7 # Output: {1, '8 ' , 6, 7, 8, 9, ' learn '}
2.7.1.12 Issubset
With se.issubset (iter obj), it is checked if all elements of se are in iter obj, T r ue
is returned, else False is returned.
1 l s t =[1, ' learn ' , 8, 9, 7, '8 ' , 7, 6]
2 se2={8,7,9}
3 se3=se2 . issubset ( l s t )
4 print(se3)
5 # Output: True
6 se1={1, ' learn ' , 8, 9, 7, '8 ' , 7, 6}
7 se3=se2 . issubset (se1)
8 print(se3)
9 # Output: True
10 se2={8,7,9,11}
11 se3=se2 . issubset ( l s t )
12 print(se3)
13 # Output: False
Function of set () as input takes an optional iterable object, and converts it to a set
object, to use it, set (iter obj) is used. In a simple statement, each element of iter obj
is placed in a position of the set. Take a look at the following examples. All built-in
functions for the set that is created with {} (with initializing value) can be applied to
the set constructor.
1 # To remove duplicate elements in a l i s t
2 l s t=set ([ ' country ' , 17, 'x ' , 17])
46 2 Python Basics
3 print( l s t )
4 # Output: { ' country ' , 17, 'x '}
5 # To remove duplicate elements in a string
6 l s t=set ( ' learning ' )
7 print( l s t )
8 # Output: { 'n ' , ' i ' , ' r ' , 'e ' , ' l ' , 'a ' , 'g '}
9 l s t=set ( ' country ' )
10 print( l s t )
11 # Output: { 'n ' , 'c ' , 'u ' , ' r ' , ' t ' , 'o ' , 'y '}
12 l s t=set ([ ' country ' ,17])
13 print( l s t )
14 # Output: { ' country ' , 17}
2.8 Dictionary
A dictionary object is another data structure in Python it can store different types of
data and when it is used that the pair of data with their attributes are needed, so-called
a pair of key-value. For example, it is supposed there is a set of words that is aimed
to get their frequency in an arbitrary text. A dictionary is the best data structure to
do this, with the keys being the words and the values being the frequencies. The
dictionary has the following features.
1. Indexable
It can access an element with its key, not the index.
2. Changeable
Elements of a dictionary can be changed by another value.
3. Non-duplicatable
A dictionary cannot have duplicate elements the same as a set.
4. Nested
A dictionary can be nested the same as a list.
To create a dictionary in Python, an open curly bracket ‘{’ and a closed curly bracket
‘}’ are used, or the dict () is used. The following examples indicate how the dictio-
naries in Python are used.
1 # Defining an empty dictionary
2 d={}
3 print(type(d))
4 # Output: <class ' dict'>
5 d={ 'x ' :4 , 1: '9 ' , 'p ' : 'o ' , 'x ' :7 , 'x ' :8}
6 print(d)
7 # Notice that the duplicated keys are removed.
8 # Output: { 'x ': 8, 1: '9 ' , 'p ': 'o '}
The indexing in the dictionaries is made as follows.
2.8 Dictionary 47
1 d={ ' argentina ' : 1, ' france ' : 2, ' Croatia ' : 3, 'morocco ' : 4}
2 print(d[ ' argentina ' ])
3 # Output: 1
4 print(d[ 'morocco ' ])
5 # Output: 4
It can be seen that for indexing in a dictionary instead of putting an integer number
into the bracket, a key is put. To insert in a dictionary, dicname[key] = obj is
used, where dicname is a variable that points to a dictionary object, key is a key
belonging to dicname, and obj is a Python object. The following examples indicate
how inserting in a dictionary is done.
1 dic={ ' argentina ' : 1, ' france ' : 2}
2 dic [ ' crotia ']=3
3 dic [ 'morocco ']=4
4 print( dic )
5 # Output: { ' argentina ': 1, ' france ': 2, ' crotia ': 3}
Also, the above approach is used to change a key in the dictionary as follows:
1 dic={ ' argentina ' : 1, ' france ' : 2, ' crotia ' : 3}
2 dic [ ' crotia ']=2
3 dic [ ' france ']=1
4 print( dic )
5 # Output: { ' argentina ': 1, ' france ': 1, ' crotia ': 2}
A nested dictionary contains other dictionaries inside it. A dictionary can be nested
as follows:
1 dic={ 'd ' : { ' argentina ' : 1, ' Croatia ' : 3}, 'x ' :7 , 'm2' : 'no '}
2 print( dic [ 'd ' ])
3 # Output: { ' argentina ': 1, ' Croatia ': 3}
The more nested, the more indices must be used to access the elements of a nested
dictionary. For example, to access ‘Croatia’ and ‘argentina’, two, and three indexes
must be used, respectively.
1 di={ 'd ' : { ' argentina ' : { 'cup ' :1} , ' Croatia ' : 3}, 'x ' :7}
2 c=di [ 'd ' ][ ' Croatia ' ]
3 print(c)
4 # Output: 3
5 c=di [ 'd ' ][ ' argentina ' ][ 'cup ' ]
6 print(c)
7 # Output:1
48 2 Python Basics
Dictionary object in Python has some built-in functions that are to be described with
some examples. In all examples, dic is a dictionary object, iter obj is an iterable
object, and obj is a Python object.
2.8.2.1 Fromkeys
2.8.2.2 Get
Function of get, takes two parameters of key and obj (optional parameter), if the
key does not exist, N one is returned, and if an optional parameter of obj is specified
and if key is not found, obj is returned. To use it, dic. f r omkeys(key, obj) is used.
The following examples indicate how get is used.
1 ' ' ' brazil does not exist in the dic dictionary ,
2 so {89: 'p '} is returned . ' ' '
3 dic=d={ ' argentina ' : 1, ' france ' : 2}
4 c=d. get ( ' brazil ' ,{89: 'p ' })
5 print(c)
6 # Output: {89: 'p '}
7 ' ' ' france exists in the dic dictionary ,
8 so i t s value is returned . ' ' '
9 dic=d={ ' argentina ' : 1, ' france ' : 2}
10 c=d. get ( ' france ' ,8)
11 print(c)
12 # Output: 2
13 dic=d={ ' argentina ' : 1, ' france ' : 2}
14 c=d. get ( ' france ' )
15 print(c)
16 # Output: 2
2.8 Dictionary 49
2.8.2.3 Update
Function of update takes an iterable object that is a pair of keys and values to add
to the existing dictionary. Still, the updates are applied to the current dictionary, and
a new one is not created. The following example indicates how update can be used.
1 dic={ ' argentina ' : 1, ' france ' : 2}
2 dic . update(c=[98])
3 print( dic )
4 # Output: { ' argentina ': 1, ' france ': 2, 'c ': [98]}
2.8.2.4 Clear
2.8.2.5 Items
To obtain all keys and values in a dictionary, item function is used, and to use it,
dic.items() is used. No argument is sent to items function. By default, the obtained
objects by items can not be visible, so to make them visible, they can be converted to
a string, and list, set, or dictionary constructor. No argument is sent to item function.
The following examples indicate how items is used.
1 dic={ ' argentina ' : 1, ' france ' : 2}
2 d=dict ( dic . items ( ) )
3 print(d)
4 # Output: { ' argentina ': 1, ' france ': 2}
5 dic=d={ ' argentina ' : 1, ' france ' : 2}
6 d=l i s t ( dic . items ( ) )
7 print(d)
8 # Output: [( ' argentina ' , 1) , ( ' france ' , 2)]
9 d=set ( dic . items ( ) )
10 print(d)
11 # Output: {( ' france ' , 2) , ( ' argentina ' , 1)}
12 d=str ( dic . items ( ) )
13 print(d)
14 # Output: dict_items ( [ ( ' argentina ' , 1) , ( ' france ' , 2)])
50 2 Python Basics
2.8.2.6 Values
To obtain all values in a dictionary, values function is used, to use it, dic.values() is
used. No argument is sent to keys function. By default, the values by values can not
be visible, so to make them visible, they can be converted to a string, list, or set. No
argument is sent to values function. The following example indicates how values
can be used.
1 dic={ ' argentina ' : 1, ' france ' : 2}
2 d=l i s t ( dic . values ( ) )
3 print(d)
4 # Output: [1 , 2]
2.8.2.7 Keys
With keys function, the keys of a dictionary are returned, and to use it, dic.keys()
is used. No argument is sent to keys function. As the obtained keys by keys can not
be visible by default, so to make them visible, they can be converted to a string, list,
or set. No argument is sent to keys function. The following example indicates how
keys can be used.
1 dic={ ' argentina ' : 1, ' france ' : 2}
2 d=l i s t ( dic . keys ( ) )
3 print(d)
4 # Output: [ ' argentina ' , ' france ']
2.8.2.8 Pop
Function of pop takes key parameter and optional parameter obj to return key, if the
key does not exist, an error is raised, and if an optional parameter of obj is specified
and if key is not found, obj is returned. To use it, dic. pop(key, obj) is used. The
following example indicates how pop can be used.
1 dic={ ' argentina ' : 1, ' france ' : 2}
2 d=dic .pop( ' iee ' ,8)
3 print(d)
4 # Output: 8
5 d=dic .pop( ' france ' )
6 print(d, dic )
7 # # Output: 2 { ' argentina ': 1}
2.9 Tuple 51
2.8.2.9 Popitem
With popitem, the last item in a dictionary is to be removed, and its key and value are
to be returned. If the dictionary is empty, an error is raised. To use it, dic. popitem()
is used. The following example indicates how popitem can be used. No argument
is sent to popitem function.
1 dic={ ' argentina ' : 1, ' france ' : 2, ' Crotia ' :3}
2 d=dic . popitem()
3 print(d)
4 # Output: ( ' Crotia ' , 3)
5 print( dic )
6 # Dictionary after removing the last item
7 # Output: { ' argentina ': 1, ' france ': 2}
To create a dictionary, dict () can be used. The dictionary constructor takes an optional
iterable object such that the iterable object must be a pair of keys and values. Take a
look at the following examples. All built-in functions for the dictionary that is created
with {} can be applied to the dictionary constructor.
1 # Defining an empety dictionary
2 d=dict ({})
3 print(type(d))
4 d=dict ( argentina=1,france=2,Croatia=3)
5 # Output: { ' argentina ': 1, ' france ': 2, ' Croatia ': 3}
6 d=dict ( [ ( ' argentina ' , 1) , ( ' france ' , 2)] , Croatia=3)
7 d=dict ( argentina=1,france=2,Croatia=3)
8 # Output: { ' argentina ': 1, ' france ': 2, ' Croatia ': 3}
9 d=dict ( [ ( ' argentina ' , 1) , ( ' france ' , 2)])
10 print(d)
11 # Output: { ' argentina ': 1, ' france ': 2}
2.9 Tuple
In this data structure, the different data types can be stored and can be indexed like
a list, but they are not mutable. In other words, once a tuple is created, it cannot be
changed such as by adding or removing. The dictionary has the following features.
52 2 Python Basics
1. Indexable
It can access an element with its index.
2. Unchangeable
Elements of a tuple can not be changed or removed, and no element can be
inserted
3. Duplicatable
A tuple can have duplicate elements the same as a list.
4. Nested
A tuple can be nested the same as a list.
To create a tuple in Python, an open parenthesis (, and a closed parenthesis ) are
used, or a tuple() is used.
Note
Note: As a tuple is immutable, there is no need to copy it, just an assignment
is enough.
The following examples indicate how the dictionaries in Python are used.
1 # Defining an empty tuple
2 t =()
3 print(type( t ))
4 # Output: <class ' tuple'>
5 t =( 'x ' , 4, 1, '9 ' , 'p ' , 'o ' , 'x ' , 9, 7, 'x ' , 8)
6 print( t )
7 # Notice that the duplicated keys are kept .
8 # Output: ( ' x ' , 4, 1, '9 ' , 'p ' , 'o ' , 'x ' , 9, 7, 'x ' , 8)
A tuple can be created without parentheses, only the elements must be separated by
commas. Take a look at the following example.
1 t= ' argentina ' , 1, ' france ' , 2, ' Croatia ' , 3, 'morocco ' , 4
2 print( t )
3 '''
4 Output: ( ' argentina ' , 1, ' france ' , 2,
5 ' Croatia ' , 3, 'morocco ' , 4)
6 '''
The indexing in the tuples is done as follows.
1 t =( ' argentina ' , 1, ' france ' , 2, ' Croatia ' , 3, 'morocco ' , 4)
2 print( t [0])
3 # Output: argentina
4 print( t [3])
5 # Output: 2
2.9 Tuple 53
A nested tuple contains other tuples inside it. The more tuple, the more index to
access an object.
1 # defining a nested tuple
2 t =( ' argentina ' , 1, ' france ' ,( ' gold ' , ' silver ' ,(2 ,4)))
3 # Accessing to elements of a nested tuple
4 ind=t [3][2][1]
5 print(ind)
6 # Output: 4
In the above example, index t[3][2][1] is used to access an element in tuple object t,
where [3] points to (‘gold’, ‘silver ’, (2, 4)), [2] points to (2, 4), and [1] points to 4.
Tuple object in Python has some built-in functions that are to be described with some
examples. In all examples, tup is a tuple object, iter obj is an iterable object, and
obj is a Python object.
2.9.2.1 Count
2.9.2.2 Index
With tuple, an iterable object is converted to a tuple that to use it, tuple(iter obj) is
used. Take a look at the following examples.
54 2 Python Basics
The range type creates a sequence of integers, which is typically used to iterate
through for loops. The range type takes integer star t parameter, and optional integer
parameters of stop and step, where star t specifies the number that the range starts,
stop specifies the number that range is ended by it, and step indicates in what interval
the numbers have appeared. If the optional parameters are not specified, the range is
stated from zero, and length range is equal to star t − 1 (as the indexes are started
from zero). By default, the numbers in the range object are not visible to make them
visible, they must be converted to a list, tuple, or set. The following examples indicate
how the range in Python is used.
1 x=range(10)
2 print(type(x))
3 # Output: <class 'range'>
1 '''
2 Converting a range object to a l i s t in an incremental way
3 '''
4 x=l i s t (range(10))
5 print(x)
6 # Output: [0 , 1, 2, 3, 4, 5, 6, 7, 8, 9]
7 # Converting a range object to a set
8 x=set (range(10))
9 print(x)
10 # Output: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
11 # Converting a range object to a tuple
2.10 Statements 55
12 x=tuple(range(10))
13 print(x)
14 # Output: (0 , 1, 2, 3, 4, 5, 6, 7, 8, 9)
In the above examples, the stop and step are not specified, so the range is started
from zero to 10 − 1. Take a look at the other examples to include stop and step in
the range object.
1 '''
2 Creating a range of numbers in range
3 10 to 16 in an incremental way
4 x=l i s t (range(10,17))
5 print (x)
6 # Output: [10, 11, 12, 13, 14, 15, 16]
7 # A range of numbers in range 10 to 16 by step 2
8 x=l i s t (range(10 ,17 ,2))
9 print (x)
10 # Output: [10, 12, 14, 16]
11 # A range of numbers in range 10 to 16 by step 3
12 x=l i s t (range(10 ,17 ,3))
13 print (x)
14 # Output: [10, 13, 16]
Also, the range function can generate integer numbers in a decremental way, as
follows.
1 # Creating a range of numbers in range 17 to 11
2 x=l i s t (range(17,10,−1))
3 print(x)
4 # Output: [17, 16, 15, 14, 13, 12, 11]
5 # Creating a range of numbers in range 17 to 11
6 x=l i s t (range(17,10,−2))
7 print(x)
8 # Output: [17, 15, 13, 11]
2.10 Statements
The concept of line in Python can be interpreted in two ways: Physical lines refer to
the visible lines of code that are written in a Python script or program. These lines
are typically separated by line breaks and can be seen when viewing the code in a
text editor or integrated development environment (IDE). Logical lines, on the other
hand, are the interpreter’s interpretation of the statement. A logical line may consist
of one or more physical lines.
A statement in Python is an instruction that is executed by the interpreter. Simple
statements are typically written on a single physical or logical line, but multiple
56 2 Python Basics
simple statements can be written on a single line if they are separated by semicolons
(;). However, it is generally not recommended to write multiple statements on a
single line, as it can make the code difficult to read and maintain. Take a look at the
following examples.
1 '''
2 ' 'a=10'' is a physical line and logical line
3 that is a simple statement
4 '''
5 a=10
6 '''
7 ' 'b=13; a=34'' is a physical line and two logical lines
8 that is a simple statement
9 '''
10 b=13; a=34
All the statements discussed in previous sections are simple statements, which are
executed one after another. However, in Python, the indentation of a line of code
is used to define a block of code, rather than using braces or other symbols like in
some other programming languages. A block of code in Python is defined by using
indentation. All the statements within a block must be indented with the same amount
of white spaces relative to the header. This is in contrast to languages like C++, where
blocks of code are defined by using braces . Another important concept in Python is
a compound statement, which is composed of several simple statements that affect
the execution of the program. Compound statements typically start with a header
that consists of a keyword followed by an expression, and end with a colon (:). The
statements that follow the header are indented with the same amount of white spaces
and are considered to be part of the block of code.
Some examples of compound statements in Python include the if statement for
conditional branching, the while and for loops for iterating over a sequence of values,
and the def keyword for defining functions.
1 # Simple statement
2 l s t =[1, ' learn ' , 8, 9, 7, '8 ' , 7, 6]
3 # Simple statement
4 se2={8,7,9}
5 # Simple statement
6 se3=se2 . issubset ( l s t )
7 # Simple statement
8 print(se3)
In the above example, it can be seen that all statements are simple and have the same
amount of indention. The following example illustrates how compound statements
are written.
1 '''
2 header is consisted with i f keyword and expression 20>18,
2.10 Statements 57
1 x=0
2 n=20
3 '''
4 header is consisted
5 with while keyword
6 and expression x <=n,
7 and is ended by : (colon)
8 '''
9 while x <=n:
10 x=x+1
11 print(n)
12 '''
13 All statements after the
14 header are in the same
15 amount of indentation
16 '''
58 2 Python Basics
1 '''
2 header is consisted with
3 for keyword and an iterable object ,
4 and is ended by : (colon)
5 '''
6 l s t =[2 ,5 ,7 ,9 ,3]
7 for i in l s t :
8 x=0
9 print( i )
10 '''
11 All statements after the header
12 are in the same amount of indentation
13 '''
2.11 Conditions
16 statement n
17 else :
18 statement 1
19 statement 2
20 statement n
21 '''
In the next, some examples of the ‘if’ structure in Python is given.
1 '''
2 Determining the maximum number
3 from three given numbers
4 '''
5 x=431
6 y=238
7 z=437
8 maximum = 0
9 i f x > y and x > z : # Header
10 maximum = x
11 e l i f y > x and y > z : # Header
12 maximum =y
13 e l i f z > x and z > y: # Header
14 maximum = z
15 print( ' ' 'The maximum number is ' , maximum ' ' ' )
16 # Output: The maximum number is 437
In the below code, a simple type checker with an ’if’ structure is provided.
1 # Type checkr
2 x= ' learn '
3 i f type(x)==int : # Header
4 print( ' ' ' the type is integer ' ' ' )
5 e l i f type(x)==float : # Header
6 print( ' ' ' the type is float ' ' ' )
7 else : # Header
8 print( ' ' ' ' ' ' the type is string ' ' ' ' ' ' )
9 # Output: the type is string
Also, an ‘if’ structure can be nested. Take a look at the following examples:
1 x= ' learn '
2 i f type(x)==int :
3 print( ' ' ' the type is integer ' ' ' )
4 e l i f type(x)==float :
5 print( ' ' ' the type is float ' ' ' )
6 else :
7 i f x== ' learning ' :
8 print( ' ' ' your strings ends with ing ' ' ' )
60 2 Python Basics
2.12 Loops
Loops are used when a block of code needs to be executed repeatedly for a specific
purpose. There are two main types of loops in Python: the while loop and the for
loop. In Python, ‘for’ is a compound statement, so all statements after the header
have the same amount of indentation relative to the header of ‘for’.
2.12.1 For
5 for j in range(6):
6 row.append(0)
7 mat.append(row)
8 print(mat)
9 '''
10 Output:
11 [[0 , 0, 0, 0, 0, 0] ,
12 [0 , 0, 0, 0, 0, 0] ,
13 [0 , 0, 0, 0, 0, 0] ,
14 [0 , 0, 0, 0, 0, 0] ,
15 [0 , 0, 0, 0, 0, 0]]
16 '''
2.12.2 Comprehensions
Comprehensions in Python are faster in terms of time and shorter code to create a
sequence of data. The following example is a way to create a sequence of data in a
list.
1 l s t =[]
2 for x in range(6):
3 l s t .append(x)
4 print( l s t )
5 # Output: [0 , 1, 2, 3, 4, 5]
The following code is an example of creating a sequence of data with a list compre-
hension. It can be seen that the code is shorter than the above code, and actually it is
faster.
1 # List comprehension
2 l s t =[x for x in range(6)]
3 print( l s t )
4 # Output: [0 , 1, 2, 3, 4, 5]
Also, many different operations with a list comprehension can be done.
1 # List comprehensions
2 l s t =[x+1 for x in range(2)]
3 print( l s t )
4 # Output: [1 , 2]
5 l s t =[x−1 for x in range(4)]
6 print( l s t )
7 # Output: [−1, 0, 1, 2]
8 l s t =[x**2 for x in range(6)]
9 print( l s t )
2.12 Loops 63
1 unsorted_list =[8,7,5,9]
2 for indexi in range(1 , len( unsorted_list ) ) :
3 currentkey=unsorted_list [ indexi ]
4 prevind=indexi−1
5 while prevind>−1 and currentkey<unsorted_list [prevind ] :
6 unsorted_list [prevind+1]=unsorted_list [prevind]
7 prevind=prevind−1
8 unsorted_list [prevind+1]= currentkey
9 print( unsorted_list )
2.13 Functions
A function is a block of code that performs a specific task and usually returns a
result. There are two main types of functions: built-in functions and user-defined
functions. Built-in functions are pre-defined functions that can be executed simply
by referencing them, whereas user-defined functions are defined and executed by
the user. There are many built-in functions available, and investigating all of them
is beyond the scope of this study. However, we will describe some of them with
examples below. In the below examples, iter obj is an iterable object. Taking the
maximum of the given numbers is with max(iter obj).
1 t =[4,7,9,3]
2 # Taking the maximum number from a l i s t
3 m=max( t )
4 print(m)
5 # Output: 9
6 # Taking the maximum number from a set
7 t ={4,7,9,3}
8 m=max( t )
9 print(m)
10 # Output: 9
11 # Taking the maximum number from a tuple
12 t =(4,7,9,3)
13 m=max( t )
14 print(m)
15 # Output: 9
Taking the summation of the given numbers is with sum(iter obj).
1 t =[4,7,9,3]
2 # Taking the maximum number from a l i s t
3 s=sum( t )
4 print( s )
5 # Output: 23
2.13 Functions 65
18 (2 , 'c ')
19 (3 , ' s ')
20 '''
To obtain the object and the index separately in the for loop, two variables are used
as follows.
1 s= ' cs '
2 for i , j in enumerate(s , 2 ) :
3 print( i , j )
4 '''
5 # Output:
6 2 c
7 3 s
8 '''
The above built-in functions were written by others, but Python users themselves
can create functions called user-define functions. The following notes depict how the
user-defined function is defined. In Python, user-defined functions are the compound
statement, which means that after defining the header, all statements after the header
have the same amount of indentations.
1 ''' '''
2 def is a keyword,
3 FunctionName is the name that the user chooses ,
4 parameter is to import the data from the arguments ,
5 return is the result that
6 inside the function is computed.
7 ''' '''
8 '''
9 # Header
10 def FuncName (parameter1 , parameter2 , . . . ,parametern):
11 statemnt 1
12 statement 2
13 .
14 .
15 .
16 statement n
17 return result
18 ' ' '
In Python, if no argument is sent to the function, its default parameters are considered,
otherwise, the arguments sent are used. Take a look at the following example.
1 # Parameters are operator ' ,operrand1 , operand2
2 def SimpleCalc( operator= '+ ' ,operrand1=20, operand2=16):
3 i f operator== '+ ' :
4 res=operrand1+operand2
68 2 Python Basics
The variable that points to the objects of a string, set, list, object, etc, its scope can
be local or global. The Local variables are only used within functions, while global
variables can be used throughout the program. For example, the following code will
raise an error, because r is a local variable and just can be used in the function.
1 def add(a ,v) :
2 c=a+v
3 r=4
4 r=r *v
5 return c
2.13 Functions 69
6 d=add(11,9)
7 print( r )
8 # Output: NameError: name ' r ' is not defined
With global keyword, the local variable inside a function can be used as a global.
1 def add(a ,v) :
2 c=a+v
3 global r
4 r=4
5 r=r *v
6 return c
7 d=add(11,9)
8 print( r )
9 # Output: 36
The next example indicates how the numbers are sorted using a user-defined function.
1 def insertion_sort ( unsorted_list ) :
2 for indexi in range(1 , len( unsorted_list ) ) :
3 currentkey=unsorted_list [ indexi ]
4 PreInd=indexi−1
5 while PreInd>−1 and currentkey <unsorted_list [PreInd ] :
6 unsorted_list [PreInd+1]=unsorted_list [PreInd]
7 PreInd=PreInd−1
8 unsorted_list [PreInd+1]= currentkey
9 return unsorted_list
10 t=insertion_sort ([4 ,7 ,9 ,0 ,3 ,31])
11 print( t )
12 # Output: [0 , 3, 4, 7, 9, 31]
The lambda function is a simple way to define a function in Python. It is often called
an anonymous function because it has no name. Lambda functions are useful when
a small, simple function is needed and there is no need to define a separate function
using the def keyword. A lambda function can take any number of arguments, but it
can only evaluate one expression. The syntax for a lambda function is lambda argu-
ments: expression. The arguments are separated by commas, and the expression is
evaluated and returned when the lambda function is called. Unlike regular functions,
there is no need to use the return keyword in a lambda function because it automati-
cally returns the result of the expression. The following note depicts the structure of
’lambda’ in Python.
1 '''
70 2 Python Basics
Note
Note: The br eak and continue just work if they are used in the loops.
2.13.3.1 Continue
In the below example, with continue keyword, if a number is even it is ignored, and
the loop until the end is continued.
2.13 Functions 71
2.13.3.2 Break
In the below example, with br eak keyword, if just an even number is found, the loop
is terminated, which 6 is found, and the loop is terminated.
1 l s t =[5 ,6 ,2 ,3 ,0 ,13 ,4]
2 lst0 =[]
3 for i in l s t :
4 i f i%2==0:
5 break
6 lst0 .append( i )
7 print( lst0 )
8 # Output: [5]
With pass keyword, nothing is done, as follows.
1 l s t =[5 ,6 ,2 ,3 ,0 ,13 ,4]
2 lst0 =[]
3 for i in l s t :
4 i f i%2==0:
5 pass
6 lst0 .append( i )
7 print( lst0 )
8 # Output: [5 , 6, 2, 3, 0, 13, 4]
When running a program, errors may occur that prevent the program from running.
In Python, errors can be handled with tr y and except structures. It is a compound
statement, which means all statements after the header have the same amount of
indentation. The following note depicts how tr y and except work.
1 '''
2 try : # Header
3 statement 1
72 2 Python Basics
4 statement 2
5 .
6 .
7 .
8 statement n
9 except ExceptionName 1: # Header
10 statement 1
11 statement 2
12 .
13 .
14 .
15 statement n
16 except ExceptionName 2: # Header
17 statement 1
18 statement 2
19 .
20 .
21 .
22 statement n
23 except ExceptionName 3: # Header
24 statement 1
25 statement 2
26 .
27 .
28 .
29 statement n
30 '''
In Python, errors can occur for various reasons, including value, type, index, etc.
Hence, there are different exceptions to handle each error. Consider the following
example to see how it works.
1 '''
2 In a try−except block , each statement can
3 be written within the try block and will
4 be executed unless an exception is raised .
5 '''
6 a=10
7 b=21
8 try :
9 c=a+b+ 'b '
10 print(c)
11 # I f a value error occurs ,
12 # an alert will be raised through printing
13 except ValueError :
14 print( ' ' ' Value Error ' ' ' )
2.14 Modules 73
2.14 Modules
A module is a collection of code that contains a set of predefined functions that can
be used by importing. To import a module, the import keyword is used, followed by
the name of the module, import libname that import is a keyword, and libname is
a library name. For example, the math module can be imported using import math.
Once a module is imported, the functions and variables defined in the module can
be accessed using the dot notation. For example, the sqrt() function from the math
module can be accessed using math.sqrt(4).
The following examples indicate how the libraries are imported. The math library
is used for importing the math functions.
1 import math
2 # Computing cosine
3 t=math. cos(2.8)
4 print( t )
5 # Output: −0.9422223406686581
74 2 Python Basics
2.15 Generators
entire dataset. The syntax for generators is similar to that of functions, with the key
difference being the use of the “yield” keyword instead of “return”. To illustrate this
concept, consider the Python code in Code 2.2. This code employs a generator to
produce an iterator containing 10 billion numbers. If this were done using a regular
function, it would result in a memory error.
Code 2.2 An example of generators in python
1 def gen1(n) :
2 a=0
3 number=0
4 while a<n:
5 a=a+1
6 yield number
7 number=number+1
8 s=gen1(10000000000)
In Code 2.2, as long as a < n, yiled generated a number.
2.16 Recursion
Also, the following code computes the nth Fibonacci number using recursion.
1 '''
2 Calculating the n−th Fibonacci
3 number using recursion
4 '''
5 def fibonacci (n) :
6
7 '''
8 Check i f n is less than
9 or equal to 1 (base case)
10 '''
11 i f n <= 1:
12 # Return n as the Fibonacci number
13 return n
14 '''
15 I f n is greater than 1, calculate
16 the Fibonacci number recursively
17 '''
18 else :
19 # Add the two previous Fibonacci numbers
20 return fibonacci (n−1) + fibonacci (n−2)
Chapter 3
Math
3.1 Josephus
Table 3.1 The expected outputs for certain inputs for Josephus problem
n, k Expected output
6, 2 [2, 4, 6, 3, 1, 5]
5, 2 [2, 4, 1, 5, 3]
8, 8 [8, 1, 3, 6, 5, 2, 7, 4]
3, 9 [3, 1, 2]
4, 3 [3, 2, 4, 1]
the indexes are reset, as it is a circle, so in the previous step, k = 1. Now in the set
of men, there are x3 and x5 , and k = 1. K is incremented by two, so x5 is found,
and removed, so ex = [2, 4, 1, 5]. In the last, x3 is executed, and in the execution
order is ex = [2, 4, 1, 5, 3]. For some inputs, the expected outputs are illustrated in
Table 3.1.
Algorithm
It takes two arguments: n, the number of people in the circle, and k, the number of
people to skip before eliminating the next person. It creates a list m of the numbers
from 1 to n, representing the people in the circle. The algorithm then repeatedly
eliminates the k-th person from the circle until only one person remains, and returns
a list of the order in which the people were eliminated. It uses the modulo operator
to ensure that the index i wraps around to the beginning of the list when it reaches
the end. The algorithm steps are outlined in detail as follows:
1. It takes two values n and k.
2. Create a list named m that contains all the numbers from 1 to n.
3. Create an empty list named ans to store the output.
4. Set the variable i to 0.
5. Create a while loop that will continue until the list ‘m’ becomes empty.
6. Within the while loop, by utilizing Eq. 3.1, update i by adding k to it and subtract-
ing 1. Then take the modulo of the length of m to ensure that i remains within the
bounds of the list.
7. Use the pop method on the m list to remove the element at index i and append it
to the ans list.
8. Return the ans list as the output of the function.
Code 3.1 depicts the Python code for Josephus’s problem.
(i + k − 1) mod m (3.1)
80 3 Math
result modulo the length of the remaining list m. It then appends the number at the
calculated index to the ans list and removes it from the m list using the pop method.
Finally, the function returns the ans list containing the order in which the people
were executed.
Let the point (x,y) be in a lattice grid that consisted of the pairs of natural numbers,
and one want to reach to point (0,0). At each point, the movement must be either left
or down. Write a function that counts the highest number of states that can be passed
so that the point does not exceed the coordinates in the taboo list. As input, x and
y are the coordinates and tabu is the list of forbidden points. For some inputs, the
expected outputs are illustrated in Table 3.2.
Algorithm
Table 3.2 The expected outputs for certain inputs for Lattice Path
x, y, tabu Expected output
3, 2, [] 10
1, 6, [(7, 1), (4, 4)] 7
8, 8, [(9, 10), (1, 4)] 11220
7, 5, [6,8] 792
82 3 Math
Code 3.2 depicts the Python code for the Lattice path problem.
Code 3.2 Python code for lattice path problem
1 def l a t t i c e _ p a t h s (row , col , tabu ) :
2 '''Create a 2D array with size (row+1) x (col+1)
3 and initialize all values to zero
4 '''
5 paths = [ [ 0 ] * ( col +1) for _ in range (row+1)]
6
7 '''Set the value of the top-left corner cell to 1,
8 since there is only one way to reach it
9 '''
10 paths [ 0] [ 0] = 1
11
12 '''Fill in the first column of the table,
13 skipping any cells that are in the 'tabu' list '''
14 for i in range (1 , row+1):
15 i f ( i , 0) not in tabu :
16 paths [ i ] [ 0 ] = paths [ i −1][0]
17
18 '''Fill in the first row of the table,
19 skipping any cells that are in the 'tabu' list
20 '''
21 for j in range (1 , col +1):
22 i f (0 , j ) not in tabu :
23 paths [ 0 ] [ j ] = paths [ 0 ] [ j −1]
24
25 # Fill in the rest of the table
26 for i in range (1 , row+1):
27 for j in range (1 , col +1):
28 # Skip any cells that are in the 'tabu' list
29 i f ( i , j ) not in tabu :
30 '''The value of each non-border cell
31 is the sum of the value of the cell
32 above it and the cell to the left of it.'''
33 paths [ i ] [ j ] = paths [ i −1][ j ] + paths [ i ] [ j −1]
34
35 return paths [row ] [ col ]
In this challenge, a function must be created for the Brussel choice problem. The
function takes positive integers n, mink, and maxk as input parameters and generates
a sorted list of all positive integers n for which there exists a subset m that can take
3.3 Brussel Choice Problem 83
Table 3.3 The expected outputs for certain inputs for Brussel Choice
n, mink, maxk, Expected output
10, 2, 5 [5, 20]
9, 1, 4 18
47, 1, 1 [27, 87, 414]
100, 84, 99 []
on values of either 2 times m or the fraction m/2. The resulting list is required to be
in ascending order while ensuring that the subset m falls within the range of mink
and maxk. For some inputs, the expected outputs are illustrated in Table 3.3.
Algorithm
In general, the algorithm creates a numerical list through specific operations per-
formed on the digits of the input number ‘n’. The said operations comprise dividing
a subset of digits by 2 or multiplying it by 2 based on whether the subset represents an
even or odd integer. Subsequently, the resultant numerical list is sorted in ascending
order. The algorithm steps are outlined in detail as follows:
1. The algorithm takes three parameters: ‘n’, ‘mink’, and ‘maxk’.
2. Initialize an empty list called ‘result’.
3. Convert the input integer ‘n’ to a list of its digits using list comprehension and
save it to the variable ‘digits’.
4. Iterate over ‘k’ from ‘mink’ to ‘maxk+1’.
5. For each value of ‘k’, iterate over ‘i’ from 0 to ‘len(digits)-k+1’.
6. Extract the sub-list of digits from index ‘i’ to ‘i+k-1’, convert it to an integer and
save it to the variable ‘digit’.
7. Check if ‘digit’ is even. If so, compute half of ‘digit’ and save it to the variable
‘half_digit’.
8. Create a new list called ‘new_digits’ which consists of the first ‘i’ elements of
‘digits’, followed by the digits of ‘half_digit’, followed by the remaining elements
of ‘digits’.
9. Convert ‘new_digits’ to an integer and save it to the variable ‘new_num’.
10. Append ‘new_num’ to the list ‘result’.
11. Create a new integer called ‘nd’ which is twice ‘digit’.
12. Create a new list called ‘new_digits’ which consists of the first ‘i’ elements of
‘digits’, followed by the digits of ‘new_digit’, followed by the remaining elements
of ‘digits’.
13. Convert ‘new_digits’ to an integer and save it to the variable ‘new_num’.
14. Append ‘new_num’ to the list ‘result’.
15. Sort the list ‘result’ using the insertion sort algorithm in an ascending order.
16. Return the sorted list ‘result’.
84 3 Math
Code 3.3 depicts the Python code for the Brussel choice problem.
Code 3.3 Python code for brussels choice problem
1 def i n s e r t i o n _ s o r t ( a r r ) :
2 for i in range (1 , len ( a r r ) ) :
3 k = arr [ i ]
4 j = i − 1
5 while j >= 0 and k < a r r [ j ] :
6 a r r [ j + 1] = a r r [ j ]
7 j −= 1
8 a r r [ j + 1] = k
9 return a r r
10
11 def brussels_choice_problem (n , min_k , max_k ) :
12 res = [ ]
13 d i g i t s = [ int (d) for d in str (n ) ]
14 for k in range (min_k , max_k+1):
15 for i in range ( len ( d i g i t s)−k+1):
16 d = int ( ' ' . join ( str (d)
17 for d in d i g i t s [ i : i+k ] ) )
18 i f d % 2 == 0:
19 hd = d / / 2
20 new_digits = d i g i t s [ : i ] + \
21 [ int (d) for d in str (hd ) ] + d i g i t s [ i+k : ]
22 new_num = int ( ' ' . join ( str (d)
23 for d in new_digits ) )
24 res . append (new_num)
25 nd = d * 2
26 new_digits = d i g i t s [ : i ] + \
27 [ int (d) for d in str (nd ) ] + d i g i t s [ i+k : ]
28 new_num = int ( ' ' . join ( str (d)
29 for d in new_digits ) )
30 res . append (new_num)
31 res = i n s e r t i o n _ s o r t ( res )
32 return res
The Collatz conjecture is a mathematical statement that asserts that any integer
smaller than 268 , satisfying the two conditions specified in Eq. 3.2, will eventually
reach the number 1 after a finite number of steps. The conjecture deals with sequences
and can be expressed as follows: Begin with a natural number n, then generate two
3.4 Inverse Collatz Conjecture 85
Table 3.4 The expected outputs for certain inputs for inverse collatz conjecture
Shape Expected output
‘dd’ 4
‘uudduuudd’ None
‘ududududddddudddd’ 15
‘uduuddduddduu’ None
numbers for each number according to Eq. 3.2. Repeat this process for all subsequent
numbers until the sequence ends with 1.
Your task in this challenge is to write a function that computes the inverse of
the Collatz conjecture. If the computation yields an invalid result (i.e., a non-integer
number), your function should return None. The inverse of the Collatz conjecture
doubles even numbers and subtracts 1 and divides odd numbers by 3. Formally,
the Collatz conjecture is represented in Eq. 3.2, while the inverse of the Collatz
conjecture is represented in Eq. 3.3. For certain inputs, expected outputs are provided
in Table 3.4. For example, if shape = ududddd is the given string, compute the
inverse of the collatz conjecture. In the first step, it visits d, according to Eq. 3.3,
multiplication is done, so x = x × 2. In the next step, three consecutive d are visited
that x is updated as follows, x = 2 → 2 ∗ 2 = 4, x = 4 → 4 ∗ 2 = 8, x = 8 →
8 ∗ 2 = 16. In the next step, u is visited and according to Eq. 3.3, division is done,
so x = 16 → (16 − 1)/3 = 5, again, a d is visited and x = 5 → 5 ∗ 2 = 10. In the
last, one u is visited, so x = 10 → (10 − 1)/3 = 3. Therefore, the inverse of collatz
conjecture for shape = ududddd is 3. To check if the obtained inverse is correct,
the shape of the given string in the inverse of collatz conjecture must be equal to
its shape in collatz conjecture. In this regard, according to Eq. 3.2, while x is not
reached to 1, the string is traversed to obtain the shape. From the previous step,
x = 3 and let t be an empty string; hence, num = x, (num mod 2) = 1, so num =
(3 ∗ num + 1) → num = (3 ∗ 3 + 1), and t = u. Again, num = 10, 10 mod 2 =
0, so 10/2 = 5, and t = ud. In the next step, num = 5, and is still unequal to 1,
so num/mod2 = 1, and num = 5 ∗ 3 + 1 = 16, and t = udu. The other steps are
as follows: num = 16 mod 2 = 0 → num = num/2 = 8 → t = udud, num = 8
mod 2 = 0 → num = num/2 = 4 → t = ududd, num = 4 mod 2 = 0 → num =
num/2 = 2 → t = ududdd, num = 2 mod 2 = 0 → num = num/2 = 1 → t =
ududddd. Now, num is equal to 1, so the checking process, if the given string in
the inverse of collatz conjecture, and collatz conjecture are equal, is finished. To this
end, t is equal to shape, which means, the obtained inverse of collatz conjecture is
correct.
x/2 i f x%2 == 0
x= (3.2)
3x + 1 i f x%2 == 1
2x i f x%2 == 0
x= (3.3)
(x − 1)/3 i f x%2 == 1
86 3 Math
Algorithm
The algorithm to solve this problem is to transform an input string comprising solely
of ‘u’ and ‘d’ characters into a numerical value using the inverse of the Collatz
conjecture. To begin with, the algorithm initializes x as 1.0 and proceeds to process
each character in the input string from right to left. If the current character is ‘d’,
the algorithm doubles x. Conversely, if the character is ‘u’, it reduces x based on the
inverse of the Collatz conjecture. In case the preceding value of x is not an integer,
the algorithm returns None. Subsequently, once all characters have been processed,
the algorithm verifies that x is neither equal to zero nor empty. Finally, the algorithm
computes the expected outcome by applying the Collatz conjecture to the generated
number and compares it with the original input string. If both match, the algorithm
returns the computed number as an integer. Otherwise, it returns None. The Python
code for collatz conjecture is depicted in Code 3.4.
Code 3.4 Python code for inversing collatz conjecture
1 def check_if_integer (number ) :
2 '''
3 Check if a number is an integer by
4 checking the remainder when divided by 1
5 '''
6 i f number % 1 == 0:
7 return True
8 else :
9 return False
10
11 def pop_last_item ( i n p u t _ l i s t ) :
12 # Get and remove the last item from the input list
13 l i s t _ l e n g t h = len ( i n p u t _ l i s t )
14 last_item = i n p u t _ l i s t [ l i s t _ l e n g t h −1]
15 del i n p u t _ l i s t [ l i s t _ l e n g t h −1]
16 return last_item
17
18 def Inverse_collatz_conjecture ( shape ) :
19 '''
20 Convert the input to a list of
21 characters and initialize x to 1.0
22 '''
23 shape_list = l i s t ( shape )
24 x = 1.0
25
26 # Iterate over each character in the input list
27 while shape_list :
28 item = pop_last_item ( shape_list )
29 i f item == ' d ' :
3.4 Inverse Collatz Conjecture 87
On a two-dimensional integer grid, a corner is defined as three points of the form (x,
y), (x, y + h), and (x + h, y) for some value of h greater than 0. These points form
a carpenter’s square or a chevron shape that points towards the southwest, with the
point (x, y) serving as the tip and (x, y + h) and (x + h, y) defining its axis-aligned
wings of equal length. Write a function that as input take a list of points sorted by
their x-coordinates, ties broken by y-coordinates, and returns the number of possible
corners. For some inputs, the expected outputs are illustrated in Table 3.5.
Algorithm
The algorithm to count the possible corners is to find all 3-point combinations in
the list of points that form a carpenter’s square or chevron shape as described in the
problem statement. The algorithm steps are outlined in detail as follows:
1. initialize a variable named counter to zero.
2. Iterate over each point in the list of points using a nested loop.
3. For each point, check if there exists another point with a larger x-coordinate and
the same y-coordinate.
4. If such a point exists, check if the third point needed to form a corner (as per the
definition provided in the problem) is also present in the list of points.
5. If the third point exists, increment the counter variable by 1.
6. Return the final value of the counter .
The Python code for counting possible corners is depicted in Code 3.5.
Code 3.5 Python code for counting corners
1 def counting_possible_corners ( points ) :
2 counter = 0
3 for x , y in points :
4 for x2 , y2 in points :
5 i f x2 > x and y2 == y and \
6 (x + y2 − y , y + x2 − x) in points :
7 counter += 1
8 return counter
Table 3.5 The expected outputs for certain inputs for counting possible corners
Points Expected output
[(1, 1), (3, 5), (5, 2)] 4
[(0, 4), (0, 16), (2, 2), (2, 5), (5, 2), (9, 13)] 1
[(1, 3), (1, 7), (5, 3), (5, 5), (7, 3)] 15
3.6 Nearest S-gonal 89
Table 3.6 The expected outputs for certain inputs for finding nearest S-gonal
n, sides Expected output
7, 8 8
1, 19 1
15, 18 18
87, 36 105
Let s > 2 be a positive integer that defines the infinite sequence of s-gonal numbers,
where the i-th element is represented by Eq. 3.4. Write a function that as input takes
sides s and a positive integer n, and return the Nearest s-gonal integer to n. If there
are two s-gonal numbers, the smaller one must be returned. For some inputs, the
expected outputs are illustrated in Table 3.6.
((s − 2) × i 2 ) − ((s − 4) × i)
(3.4)
2
Algorithm
In order to find the polygonal number closest to a given number ‘n’ with a specified
number of sides ‘sides’. The algorithm follows a three-step process. Firstly, it com-
putes the polygonal number for a specific index by employing the equation Eq. 3.4.
Secondly, it utilizes binary search to identify the middle index that corresponds to
the polygonal number closest to ‘n’. Lastly, the distances between the polygonal
numbers and ‘n’ are calculated for the three indices that surround the middle index
obtained through binary search, and the polygonal number that is nearest to ‘n’ is
returned.
The Python code for finding nearest polygonal number is depicted in Code 3.6.
Code 3.6 Python code for finding nearest s-gonal number
1 def nearest_polygonal_number (n , sides ) :
2 # Calculating polygonal numbers
3 def calculate_polygonal_number ( index ) :
4 return ( ( sides − 2) *
5 index ** 2 − ( sides − 4) * index ) / / 2
6
7 # Determine upper bound for binary search
8 upper_bound = 1
9 while calculate_polygonal_number ( upper_bound ) <= n :
10 upper_bound *= 2
11
90 3 Math
Term ‘Fulcrum’ refers to the point of balance within a list of weights, where the total
weight on its left side is equal to the total weight on its right side. This challenge
requires identifying a position in a non-empty list of numerical values that can serve
as the fulcrum and balance the weight on both sides. According to the principles of
physics, a board achieves equilibrium when the forces acting on either side of its
3.7 Finding Fulcrum Position 91
Table 3.7 The expected outputs for certain inputs for finding fulcrum positions
Weights Expected output
[6, 6, 9] −1
[43, 51, 35, 4] 1
[19, 25, 5, 42, 38, 8, 34, 16, 14, 8, 47, 42, 4, 20, 7
23]
[7, 24, 3, 38] 2
support are equal. To meet this objective, you must create a function that takes a list
of numbers as input and returns the position of the fulcrum that balances the weights
as output. In cases where no such position exists, the function should return −1.
Algorithm
4 for j in range ( i ) )
5 right_weight_sum = sum( weights [ j ] * ( j−i )
6 for j in range ( i +1, len ( weights ) ) )
7 i f left_weight_sum == right_weight_sum :
8 return i
9 return −1
In this challenge, there is a pyramid constructed using spheres. The pyramid has
n rows and m columns of spheres on the top level, and each subsequent level has
one additional row and column of spheres compared to the previous level. You are
requested to write a function that takes in the dimensions n and m as well as the
height h, and computes the total number of blocks required to build such a pyramid.
For some inputs, the expected outputs are illustrated in Table 3.8.
Algorithm
To calculate the total number of spheres required, the algorithm utilizes a set of
formulas that take into account the number of rows and columns in each level of the
pyramid, as well as the height of the pyramid. Outlined below are the detailed steps
involved in the algorithm:
1. Subtract 1 from the input height ‘h’. The bottom-most layer is counted as the
first layer and the top-most layer is counted as the (h + 1)th layer. However, the
formula used in the code assumes that the bottom-most layer is the 0th layer and
the top-most layer is the h-th layer. Therefore, to make the height ‘h’ consistent
with the formula used, we need to subtract 1 from the input height ‘h’ (i.e., ‘h
+1 − 1’ or ‘h’).
2. Compute the total number of blocks required using the following formula: a =
m ∗ n ∗ (h + 1)
Table 3.8 The expected outputs for certain inputs for problem of spheres in pyramids
n, m, h Expected output
4, 2, 2 23
28, 30, 3 2699
3, 3, 3 50
2, 7, 9 654
3.8 Counting Sphere Pyramid Blocks 93
3. Add the extra blocks required for each level of the pyramid, using the following
formula: a+ = (m + n) ∗ (h ∗ (h + 1)//2). This calculates the sum of the first h
triangular numbers, multiplied by the sum of m and n.
4. Finally, add in the extra blocks required to create each layer of the pyramid, using
the following formula: a+ = (h ∗ (h + 1) ∗ (2 ∗ h + 1))//6.
5. Return the final value of a. This calculates the sum of the first h squared numbers,
divided by 6.
The Python code to compute the total number of spheres required to build a pyramid
is depicted Code 3.8.
Code 3.8 Python code for counting the number of spheres in pyramids
1 def Counting_sphere_pyramid_blocks (n , m, h ) :
2 h −= 1
3 '''
4 Formula to compute the total number
5 of blocks required to build
6 a pyramid with base dimensions
7 n by m and height h.
8 '''
9
10 a = m * n * (h + 1)
11 a += (m + n) * (h * (h + 1) / / 2)
12 a += (h * (h + 1) * (2 * h + 1)) / / 6
13 return a
94 3 Math
In this challenge, an array of n identical coins is given and needs to be divided into
g groups, where g is a positive integer greater than or equal to one. If there are any
coins left over after forming complete groups, the remaining coins in the array are
set aside and retained. To calculate the number of coins needed to form each group,
we use the formula Eq. 3.5. We repeat this grouping process until all coins have been
used up.
Your task is to write a function that takes three input parameters: n (the total
number of coins), g (the number of groups), and c (a constant) and returns an array
containing the number of remaining coins at each grouping step. If n is 0, the function
must return an empty list. For example, let n = 10, g = 3, and c = 2. The following
transition show the remaining coins at each grouping step, as follows: 10, 3, 2 → 1;
6, 3, 2 → 0; 4, 3, 2 → 1; 2, 3, 2 → 2; 0, 3, 2. Therefore, [1, 0, 1, 2] represents the
remaining coins in each step for n = 10, g = 3, and c = 2. In the first transition,
1 is obtained from (10 mod 3 = 1). In the second transition 6 is obtained from
10//3 ∗ 2 = 6, while 3 and 2 remain constant throughout the process. For some
inputs, the expected outputs are illustrated in Table 3.9.
n//g ∗ c (3.5)
Algorithm
The algorithm uses recursion to divide the coins into groups until no further groups
can be formed. The following are the detailed steps involved in the algorithm:
1. Check if the input parameter n is equal to zero. If it is, return an empty list, as
there are no coins available for splitting.
2. Calculate the number of coins that cannot constitute a complete group by com-
puting the remainder when n is divided by g. Store this value in a variable named
remain.
Table 3.9 The expected outputs for certain inputs to group coins
n, g c Expected output
255, 128, 70 [127, 70]
301, 10, 1 [1, 0, 3]
49, 49, 2 [0, 2]
10, 2, 1 [0, 1, 0, 1]
3.10 Median of Triple Medians 95
3. Compute the total number of coins required to form all complete groups by multi-
plying the number of complete groups (n//g) by the size of each group (c). Save
this value in a variable named coins_needed.
4. Recursively invoke the function with the input parameters coins_needed, g, and
c until there are no more coins remaining to group.
5. Return an array containing the number of remaining coins at each grouping step.
The Python code for grouping the coins is depicted in Code 3.9.
Code 3.9 Python code for grouping the coins
1 def Grouping_Coins (n , g , c ) :
2 i f n == 0:
3 return [ ]
4 # how many coins cannot form a complete group
5 remain = n % g
6
7 '''
8 (1) n //g:
9 denotes groups of coins can be formed.
10 (2) n //g * c:
11 denotes coins are needed to form these groups.
12 '''
13 coins_needed = (n / / g) * c
14 remaining_coins = Grouping_Coins ( coins_needed , g , c )
15 return [ remain ] + remaining_coins
This challenge requires finding the median of a list of positive integers repeatedly
until only a maximum of three numbers remain. Specifically, for each group of three
numbers, their median must be computed and used as the input for the next iteration.
This process continues until there are at most three numbers remaining, and their
median is returned as the final result.
You are requested to write a Python function that takes a list of positive integers
as input and returns the median of the last remaining numbers. For some inputs, the
expected outputs are illustrated in Table 3.10.
Algorithm
Table 3.10 The expected outputs for certain inputs to find median of medians
Items Expected output
[909, 4, 4, 7, 9, 12, 77, 45] 9
[1, 4, 90, 65, 3, 2] 4
[22, 40, 65, 80, 93, 21] 80
[100, 9, 12, 20, 3] 5
into groups of three items, computing their median, and appending it to the medians
list. The function then recursively calls itself with the medians list until there are
no more than three items remaining. When at most three items remain, the function
sorts them in ascending order and returns the middle value as the ultimate median.
1. Take the length of the input list.
2. If the length of the input list is equal to 1, return that item as the median.
3. Otherwise, create an empty list called ‘medians’ to store the medians.
4. Split the input list into sublists of three items each using a for loop and range
function with a step size of 3. Sort each sublist in ascending order and get the
middle item as the median.
5. Append each median to the ‘medians’ list.
6. Recursively call the above step until there are no more than three items left.
7. When there are at most three items remaining, sort them in ascending order and
get the middle item as the final median.
8. Return the final median as the output.
The Python code for finding the Median of medians (triple numbers) is depicted
in Code 3.10.
Code 3.10 Python code for finding the Median of triple numbers
1 def i n s e r t i o n _ s o r t ( a r r ) :
2 for i in range (1 , len ( a r r ) ) :
3 key = a r r [ i ]
4 j = i − 1
5 while j >= 0 and key < a r r [ j ] :
6 a r r [ j + 1] = a r r [ j ]
7 j −= 1
8 a r r [ j + 1] = key
9 return a r r
10
11 def median_of_medians ( items ) :
12 # Take the length of the list
13 n = len ( items )
14
15 '''
16 If there is only one item in the list,
3.11 Smallest Seven-Zero 97
In Western culture, the number seven holds significant importance and is often con-
sidered a symbol of good fortune. In contrast, the number zero is typically viewed
as undesirable. However, when these two numbers are combined to form sequences
98 3 Math
Table 3.11 The expected outputs for certain inputs to find smallest seven zero
n Expected output
25 700
49 777777
1023 777777777777777777777777777777
104 777777000
Algorithm
29 digits_min = digits_max
30 digits_max *= 10
Algorithm
To evaluate the infix expression of the given postfix an algorithm is utilized that
performs the following steps:
1. It iterates through each item in the given postfix expression.
2. If the item is an integer, it is appended to the Storage list.
3. If the item is an operator (+, −, ∗, /), the two most recent items (operands) are
popped from the Storage list.
4. The corresponding operation (+, −, ∗, /) is then performed on these two operands,
and the result is stored in the variable result, and result is then appended to the
Storage list.
5. Steps 3–4 are repeated until all items in the postfix expression have been processed.
6. Finally, the result of the evaluation is returned by popping the last item from the
Storage list.
The Python code for computing the result of converting postfix to infix and evaluating
it is depicted in Code Code 3.12.
Table 3.12 The expected outputs for certain inputs to evaluate the infix of an postfix
Postfix Expected output
[5, 6, ‘+’, 7, ‘*’] 77
[3, 7, 9, ‘*’, ‘+’] 66
[3, 7, 9, ‘/’, ‘+’] 3
[8, 2, ‘+’] 10
3.12 Postfix Evaluate 101
Code 3.12 Python code for computing the result of postfix to infix
1 def pop_last_item ( i n p u t _ l i s t ) :
2 # Get and remove the last item from the input list
3 l i s t _ l e n g t h = len ( i n p u t _ l i s t )
4 last_item = i n p u t _ l i s t [ l i s t _ l e n g t h −1]
5 del i n p u t _ l i s t [ l i s t _ l e n g t h −1]
6 return last_item
7 def postfix_evaluate ( Postfix ) :
8 '''
9 Create an empty list to
10 store operands and results
11 '''
12 Storage = [ ]
13
14 '''
15 Iterate through each item
16 in the postfix expression
17 '''
18 for item in Postfix :
19 '''
20 If the item is an integer,
21 append it to the storage list
22 '''
23 i f isinstance ( item , int ) :
24 Storage . append ( item )
25 else :
26 '''
27 If the item is an operator,
28 pop two most recent items from the storage list
29 '''
30 Number0, Number1 = \
31 pop_last_item ( Storage ) , pop_last_item ( Storage )
32 '''
33 Perform the corresponding operation on
34 the two numbers depending on the operator
35 '''
36 i f item == '− ' :
37 r e s u l t = Number1 − Number0
38 e l i f item == '+ ' :
39 r e s u l t = Number1 + Number0
40 e l i f item == ' * ' :
41 r e s u l t = Number1 * Number0
42 e l i f item == ' / ' :
43 result = \
102 3 Math
Table 3.13 The expected outputs for certain inputs to determine the stable state in Bulgarian
solitaire
Points, k Expected output
[3], 2 1
[3, 7, 8, 14], 4 0
[10, 10, 10, 10, 10, 5] ,10 74
[3000, 2050], 100 0
In this challenge, a list of n cards is given in the form of positive integers. The
objective is to generate a new list of numbers that is different from the original list
until a stable state is reached. A stable state is achieved when the elements of a list
are the same as its preceding list, but the permutations can be different. There are
two rules as follows: (1) The sum of the given list of numbers must be equal to a
triangular number. The formula for the triangular number is provided in Eq. 3.6. (2)
To create a new list in each step, one unit is subtracted from all the numbers, and
the last element of the list is set equal to the length of the previous list. If the result
of the subtraction is zero, it is removed. This process is repeated until a stable state
is reached. Hence, the problem requires finding a list that satisfies both conditions.
This process so-called is Bulgarian solitaire. For instance, if [3] be the given list of
number and k = 2, counts the number of steps to reach a stable state. First, it must
be checked if the triangular number is equal to the sum of the given list. To this
end, k × (k + 1)/2 → 2 × (2 + 1)/2 = 3, so 3 = 3. The following steps indicate
the steps to reach a stable state: [3] → [2, 1] → [1, 2, 0] → [1, 2]. As the elements
of [2, 1] and [1, 2] are equal, it reaches a stable state, although [2, 1] and [1, 2] have
different permutations. Therefore, after one step, it reached a stable state. Write a
function in that as input, takes a list of n positive integers and a triangular number
and returns the number of steps required to reach a stable state. Some examples of
the input and output of this function on the Bulgarian solitaire problem are illustrated
in Table 3.13.
k × (k + 1)
(3.6)
2
It is crucial to determine whether a stable state has been reached in this challenge.
One possible technique for doing so involves sorting the current list and comparing
3.13 Stable State in Bulgarian Solitaire 103
it with the previous list. If the two lists are the same, it indicates that a stable state has
been achieved. However, despite its seeming simplicity, this approach can be highly
complex.
To determine the state (stable or not), two algorithms are employed: ‘is_stable_
state’ and ‘Stable State Bulgarian Solitaire’.
The ‘Stable_State_in_Bulgarian_Solitaire’ algorithm has the following steps:
1. It takes two arguments, points (a list of positive integers) and k (an integer).
Initialize a variable named number _o f _moves to 0.
2. Calculate the sum of points in the input list and store it in a variable named
equation using the formula k ∗ (k + 1)//2.
3. Call the ‘is_stable_state’ algorithm that takes two arguments, points (a list of
positive integers) and k (an integer).
4. Check whether the sum of the points list equals equation. If not, return zero to
indicate that the input list is invalid. Loop until the stable state is achieved:
• Subtract 1 from each element in the points list.
• Remove any zero values in the points list.
• Append the length of the current points list to the end of the points list.
• Increment the number _o f _moves by 1.
• Check whether the current state is stable using the ‘is_stable_state’ algorithm.
5. Return the final value of number _o f _moves.
The ‘is_stable_state’ algorithm has the following steps:
1. It takes two arguments, points (a list of positive integers) and k (an integer).
2. Create an array named count with k + 1 zeros inside the function.
3. Loop through each value p in the points list and increment the corresponding
element in count if p is less than or equal to k.
4. Loop through every integer i from 1 to k, and check whether the count[i] equals
1. If not, return False indicating that the state is unstable.
5. If the loop completes without returning False, return True indicating that the state
is stable.
The python code for computing the stable state in the Bulgarian solitaire is depicted
in Code 3.13.
Code 3.13 Python code for computing the the Bulgarian solitaire
1 def Stable_State_in_Bulgarian_Solitaire ( points , k ) :
2 # Initialize the number of moves to zero
3 number_of_moves = 0
4
5 '''
6 Equation for calculating the
7 sum of points
8 '''
9 equation = k * (k + 1) / / 2
104 3 Math
10
11 def i s _ s t a b l e _ s t a t e ( points , k ) :
12 """
13 To keep track of the frequency of each integer
14 between 1 and k present in the list of points,
15 we use a counting array named 'count'. If any
16 integer appears multiple times or not at all,
17 the stable state has not yet been achieved,
18 and as a result, the function returns False.
19 Conversely, if every integer between 1 and k
20 appears exactly once, the function returns True,
21 indicating that a stable state has been reached.
22 """
23 count = [0] * (k+1)
24 for p in points :
25 i f p <= k :
26 count [p] += 1
27 for i in range (1 , k+1):
28 i f count [ i ] != 1:
29 return False
30 return True
31
32 '''
33 Check if the input points satisfy
34 the condition for Bulgarian solitaire
35 '''
36 i f sum( points ) == equation :
37 # Loop until the stable state is reached
38 while i s _ s t a b l e _ s t a t e ( points , k)!=True :
39 # Decrease the size of each pile by 1
40 for i in range ( len ( points ) ) :
41 points [ i ] −= 1
42
43 points_Length = len ( points )
44 # Remove piles with zero size
45 points = [p for p in points i f p > 0]
46
47 '''
48 Add a new pile with the
49 size of the removed piles
50 '''
51 points . append ( points_Length )
52
53 # Increment the number of moves
54 number_of_moves += 1
3.14 Computing the Rectangular Towers in Manhattan Skyline 105
55
56 # Return the total number of moves
57 return number_of_moves
There is a list of rectangular towers as (s, e, h), where s, e, and h are a start, end, and
height in the x-coordinate, respectively. Write a python function that as input, takes
tuple (s, e, h), and as an output, returns the area of the rectangular towers. Notice
that the common area of the towers should not be computed twice. For some inputs,
the expected outputs are illustrated in Table 3.14.
Algorithm
To compute the area of the given towers, two algorithms are employed: ‘divide’ and
‘Manhattan_Skyline’. The algorithm ‘divide’ has the following steps:
1. It takes two parameters, star t and end. If star t equals end, return a list con-
taining two elements: [tower s[star t][0], tower s[star t][2]] and [tower s[star t]
[1], 0].
2. Otherwise, calculate the midpoint between star t and end, and recursively call
the left and right halves of the towers list. Merge the results from the left and right
halves into a new list using the following steps:
• Compute the mid position
• Initialize an empty list called ‘merged’, and two variables i and j to 0.
• Set h1 and h2 variables to None.
• Loop over every element in the merged list by iterating over the range of len(left)
+ len(right).
Table 3.14 The expected outputs for certain inputs to compute the rectangular towers in Manhattan
skyline
Towers Expected output
[(2, 6, 98), (1, 0, 9)] 383
[ (3, 7, 1)] 4
[(−8, 6, 3), (6, 14, 11), (0, 4, −5)] 130
[(2, 550, 222), (1, 0, 4)] 121652
106 3 Math
A tuple (a, b) represents the length and width of a rectangle, respectively. In this
challenge, write a Python function that takes a tuple (a, b) as input and returns the
minimum number of steps required to convert the rectangle into a square.
The expected inputs and respective outputs are provided in Table 3.15.
Algorithm
The best approach for solving this problem is the recursive function. The aim of the
algorithm is to determine the minimum number of cuts required to divide a given
rectangular area into equal-sized squares. To achieve this, the algorithm begins by
checking if the given rectangle is already a square. If that is the case, no cuts are
Table 3.15 The expected outputs for certain inputs to cut rectangular into squares
a, b Expected output
(7, 7) 0
(17, 10) 6
(5, 3) 3
(7, 9) 5
3.15 Cut Rectangular into Squares 109
required, and the algorithm returns 0. However, if the rectangle is not a square, the
algorithm recursively divides it into smaller rectangles until they become squares.
During this process, memoization is used to store previously computed results and
avoid redundant computations. Once all the rectangles have been transformed into
squares, the algorithm compares the results obtained by cutting the final square both
horizontally and vertically. It then selects the solution with the minimum number of
cuts as the optimal solution, memoizes the result and returns it.
1. It takes ‘a’ (length), ‘b’ (width) as input.
2. Create a dictionary called ’memo’ to store values.
3. Check if both ‘a’ and ‘b’ are equal. If they are, return 0 as there are no squares to
cut.
4. Check if either ‘a’ or ‘b’ equals 1. If so, return the maximum of ‘a’ and ‘b’ minus
1 since there can only be one square in that case.
5. Create a key by making a tuple of (‘a’, ‘b’) to check if the key exists in the memo
dictionary. If it does, return the corresponding value.
6. Initialize answer as (‘a’ − 1) * ‘b’.
7. Loop through variable ‘i’, from 1 to ‘a’ // 2 + 1.
8. Calculate the minimum between answer and (‘a’ − ‘i’, ‘b’, memo) plus (‘i’, ‘b’,
memo) plus 1.
9. Loop through variable ‘i’, from 1 to ‘b’ // 2 + 1.
10. Calculate the minimum between answer and (‘a’, ‘b’ − ‘i’, memo) plus (‘a’, ‘i’,
memo) plus 1.
11. Add the key-value pair to the memo dictionary.
12. Return answer.
The Python code for computing the minimum number of states wanted to reach a
square is depicted in Code 3.15.
Code 3.15 Python code for computing the minimum number of states wanted to reach a squares
1 def RectToSquares ( a , b , memo={}):
2 '''
3 Check if the given rectangles
4 are already squares
5 '''
6 i f a == b :
7 return 0
8
9 i f a == 1 or b == 1:
10 return (max( a , b) − 1)
11
12 key = ( a , b)
13 '''Check if we have already computed
14 the answer for this input
15 '''
16 i f key in memo:
110 3 Math
Table 3.16 The expected outputs for certain inputs to eliminate corners
Points Expected output
[(3, 3), (3, 8), (8, 3)] 1
[(0, 1), (4, 5), (3, 2)] 0
[(5, 0), (1, 3), (1, 4), (2, 0), (2, 2), (2, 3), (4, 0), 2
(4, 0)]
Algorithm
To eliminate all corners formed by three points in a given list of points, while min-
imizing the number of removed corners, the algorithm first identifies all possible
corners that can be formed by three points in the input list using nested loops. It then
utilizes recursion with memoization to determine the minimum number of corners
that must be removed to eliminate all corners from the list. The Python code for
counting the minimum number of points to remove all corners is depicted in Code
3.16.
Code 3.16 Python code for counting the minimum number of points to eliminate all corners
1 '''
2 Recursively remove the minimum number of corners
3 '''
4 def MinCornerRemover( corners , memo) :
5 '''
6 Base case: if the list of corners is empty,
7 no removals are needed
8 '''
9 i f len ( corners ) == 0:
10 return 0
112 3 Math
11
12 '''
13 Check if the current list of corners
14 has been processed before
15 '''
16 key = tuple ( corners )
17 i f key in memo:
18 return memo[ key ]
19
20
21 removals = len ( corners )
22
23 '''
24 Initialize a set to keep track of points
25 that have already been processed
26 '''
27 points_set = set ( )
28 # Loop through each corner in the list
29 for corner in corners :
30 '''
31 Loop through each point
32 in the current corner
33 '''
34 for point in corner :
35 '''
36 If the point has not been processed
37 yet, add it to the set
38 '''
39 i f point not in points_set :
40 points_set . add ( point )
41 '''
42 Compute the remaining corners
43 by excluding the current point
44 '''
45 remaining_corners = \
46 [ c for c in corners i f point not in c ]
47 '''
48 Recursively compute the minimum number
49 of removals for the remaining corners
50 '''
51 '''and add 1 to account for the
52 current point being removed
53 '''
54 removals = \
55 min(1 + MinCornerRemover
3.16 Eliminating Corners 113
In Pascal’s triangle, each number is equal to the sum of the two numbers directly
above it, whereas in Leibniz’s triangle, each number is equal to the sum of its two
bottom numbers. It is required to write a function that takes the leftmost row values
as input and returns the corresponding value of the last row at the desired position.
The expected outputs for some inputs are presented in Table 3.17.
For instance, two numerical examples of Leibniz’s triangle are depicted in Fig. 3.2.
The inputs for the first examples (A) are 2 and 3, and the position is range(2). The
numbers in the range function start from 0, so the positions of zero and one return
2 and 1, respectively.
Table 3.17 The expected outputs for certain inputs for Leibniz triangle
LeftMost_Values,Positions Expected output
[1, 2, 3], range(3) [3, −1, 0]
[4, 7, 9, 3], range(4) [3, 6, −8, 7]
[88, 90, 1, 0, 9], range(4) [9, −9, 10, 78]
[20, 95], range(2) [95, −75]
3.17 Leibniz Triangle 115
3–2=1
1 – (-1) = 2 -2 – 2 = -4 4 – (-4) = 8
Algorithm
To solve the given task, we utilize an algorithm that consists of the following steps:
1. It takes two inputs: Le f t Most_Rows, a list of values representing the leftmost
row of a Leibniz triangle, and positions, a list of integers representing positions
in the last row of the same triangle for which we want to find the values.
2. Initialize an empty list to store the result for each wanted position.
3. Initialize a dictionary to store intermediate values computed during the algorithm.
4. Compute the values in the first column of the triangle using the provided leftmost
row values.
5. Store these values in the memoization table with their corresponding indices as
keys.
6. Compute the remaining values in the triangle using the values from the previous
row.
7. Each value in the triangle is computed as the difference between the sum of the
two bottom values in the current row and the value directly above it in the previous
row.
8. Store these values in the memoization table with their corresponding indices as
keys.
116 3 Math
9. Retrieve the desired values in the last row of the triangle from the memoization
table and append them to the result list.
10. Return the list of results.
The Python code for Leibniz’s triangle is depicted in Code 3.17.
Code 3.17 Python code for Leibniz’s triangle
1 '''
2 This function takes two arguments:
3 a list of values representing
4 the leftmost row of a Leibniz triangle
5 and a list of integers representing
6 positions in the last row of the same triangle
7 for which we want to find the values.
8 '''
9 def Leibniz_triangle (LeftMost_Rows , positions ) :
10 '''
11 Initialize an empty list to store
12 the result for each position
13 '''
14 result = []
15 '''
16 Initialize a dictionary to store intermediate
17 values computed during the algorithm
18 '''
19 memo = {}
20
21 '''
22 Compute the values in the first column of the
23 triangle using the provided leftmost row values.
24 '''
25 for i in range ( len (LeftMost_Rows ) ) :
26 memo[ ( i , 0)] = LeftMost_Rows[ i ]
27
28 '''
29 Compute the remaining values in the triangle
30 using the values from the previous row.
31 '''
32 for i in range (1 , len (LeftMost_Rows ) ) :
33 for j in range (1 , i +1):
34 '''
35 Each value in the triangle is computed
36 as the difference between the sum
37 of the two bottom values
38 '''
39 value = memo[ ( i −1, j −1)] − memo[ ( i , j −1)]
3.18 Collatzy Distance 117
40 memo[ ( i , j ) ] = value
41
42 '''
43 Retrieve the desired values in the
44 last row of the triangle
45 from the memoization table and
46 append them to the result list.
47 '''
48 for i in positions :
49 r e s u l t . append (memo[ ( len (LeftMost_Rows)−1, i ) ] )
50
51 # Return the list of results.
52 return r e s u l t
Table 3.18 The expected outputs for certain inputs for Collatzy distance
Start, goal Expected output
20, 321 9
22, 15 8
4, 7 2
10, 20 2
Algorithm
To achieve the goal number for the stated challenges, a breadth-first search (BFS-
based) technique is employed. The BFS algorithm traverses all the nodes at a par-
ticular level before moving on to explore the subsequent level. In this instance,
each generated layer resulting from the application of the Collatz conjecture for-
mulas denotes a level of exploration. The algorithm initiates its exploration from
the start_num, which represents the first layer, and generates successive layers by
applying the same formulas. The following steps are involved in the algorithm:
1. It takes star t_num and goal_num (positive integers).
2. Initialize the variables num_layer s and curr _layer , where num_layer s = 0 and
curr _layer is a set containing only the starting number, i.e., start_num.
3. While the goal_num is not in curr _layer , do the following:
• Create an empty set called next_layer (As we dont need duplicated numbers).
• For each number in curr _layer , compute the the following ones:
• num//2.
• 3 ∗ num + 1.
• Add them to next_layer .
• Update curr _layer to be equal to next_layer .
• Increment num_layer s by 1.
4. Return num_layer s when goal_num is found in curr _layer .
The Python code for computing collatzy distance is depicted in Code 3.18.
Code 3.18 Python code for computing collatzy distance
1 def get_collatz_distance ( start_num , goal_num ) :
2 """
3 Takes a start number and a goal number
4 and generates all layers of positive
5 integers between them using the Collatz
6 sequence to find the shortest path from
7 start_num to goal_num.
8 """
9 # initialize the layer counter
10 num_layers = 0
3.18 Collatzy Distance 119
11 '''
12 initialize the current layer as a
13 set containing only the start_num
14 '''
15 curr_layer = {start_num}
16 '''
17 keep looping until goal_num
18 is in the current layer
19 '''
20 while goal_num not in curr_layer :
21 '''
22 initialize the next layer
23 as an empty set
24 '''
25 next_layer = set ( )
26
27 for num in curr_layer :
28 '''generate the next numbers in
29 the Collatz sequence for each number
30 in the current layer
31 '''
32 next_layer . update ( [
33 num / / 2 ,
34 3 * num + 1
35 ])
36 '''
37 set the current layer to be the
38 newly generated layer
39 '''
40 curr_layer = next_layer
41 '''
42 increment the layer counter
43 '''
44 num_layers += 1
45 '''
46 return the number of layers
47 it took to reach goal_num
48 '''
49 return num_layers
120 3 Math
Table 3.19 The expected outputs for certain inputs for the problem of sum of two squares
n Expected output
50 (7,1)
145 (12, 1)
1480 (38, 6)
540 None
In this challenge, you will be given a positive integer ‘n’ and your task is to calculate
the squares of two numbers that add up to ‘n’. For example, if ‘n’ is equal to 145, the
answer would be (12,1). If there are multiple answers, the answer with the highest
maximum number should be selected. For example, when ‘n’ is equal to 50, there are
two possible answers: (7,1) and (5,5). As 7 is greater than 5, the answer should be
(7,1). You are required to write a function that takes a positive integer ‘n’ as input and
returns the two numbers whose squares add up to ‘n’. If there are no such numbers,
the function should return ‘None’. The expected inputs and outputs for some test
cases are illustrated in Table 3.19.
Algorithm
The algorithm finds the bases by first setting a maximum value for the first base,
then checking all candidate values for the second base. If a candidate value for the
second base leads to a pair of bases that satisfy the conditions, the function returns
this pair. The following provides an outline of the algorithm’s steps.
1. It takes a positive integer n.
2. Calculate the maximum value of the first base as the square root of half of n.
3. Create a set of candidate values for the second base from 1 to the maximum value
of the first base.
4. Loop through the candidate values of the second base.
5. For each candidate value of the second base, calculate the difference between n
and the square of the second base.
6. Calculate the square root of the difference.
7. Check if the square of the root equals the difference.
8. If it does, return the pair of bases whose squares sum up to n.
9. If no such pair exists, return None.
The Python code for computing the sum of two squares is depicted in Code 3.19.
Code 3.19 Python code for computing the sum of two squares
1 def get_squares_summing_to_n (n ) :
2 """
3.20 Has Three Summer 121
Table 3.20 The expected outputs for certain inputs for three summer problem
ListNumbers, goal Expected output
[3, 5, 6, 8, 9, 21], 14 True
[2, 4, 8, 16, 32], 16 False
[550, 600, 2000, 3000, 4000], 900 False
[1, 2, 16, 79, 80, 340], 83 True
Algorithm
There is a solution that employs three nested for loops to traverse all the numbers
and compare their sum with the target number. Although this method is simple but
has high time complexity. To reach the outlined task, an algorithm is utilized that
includes following steps.
1. It takes a sorted list of numbers and a target number as input.
2. Check if the length of the input list is less than 3. If it is, return False.
3. Iterate through the sorted list one by one.
4. For each number in the list, compute the new target number by subtracting the
current number from the goal number.
5. In the next step, the algorithm utilizes the two summer algorithm to reach the
answer. Two summer takes a list of numbers and a target number as input, and
returns True if any two numbers in the list add up to the target number. Otherwise,
it returns False.
6. The two summer algorithm has the following steps:
a. Check if the length of the input list is less than 2. If it is, return False.
b. Initialize two pointers, one at the start of the list and the other at the end of the
list.
c. While the start pointer is less than the end pointer:
1. Compute the sum of the two numbers at the current positions of the start
and end pointers.
2. If the sum equals the target number, return True.
3. If the sum is less than the target number, increment the start pointer to move
to a larger number.
4. If the sum is greater than the target number, decrement the end pointer to
move to a smaller number.
d. If no match was found, return False.
7. If such a pair exists, return True.
8. If no match was found for any number in the list, return False.
The Python code for computing three summers is depicted in Code 3.20.
Code 3.20 Python code for computing three-summers
1 def has_two_sum(numbers , t a r g e t ) :
3.20 Has Three Summer 123
2 '''
3 If the length of the list
4 is less than 2, it is not
5 possible to find two numbers
6 that add up to target
7 '''
8 i f len (numbers) < 2:
9 return False
10
11 '''Initialize pointers at the
12 start and end of the list
13 '''
14 start = 0
15 end = len (numbers) − 1
16
17 '''Keep moving the pointers until
18 they meet in the middle
19 '''
20 while s t a r t < end :
21 two_sum = numbers[ s t a r t ] + numbers[ end ]
22
23 '''If the sum of the two numbers
24 equals target, we have found a match
25 '''
26 i f two_sum == t a r g e t :
27 return True
28
29 '''If the sum is less than target,
30 increment the start pointer to
31 move to a larger number
32 '''
33 e l i f two_sum < t a r g e t :
34 s t a r t += 1
35
36 # If the sum is greater than target,
37 #decrement the end pointer to move
38 #to a smaller number
39 else :
40 end −= 1
41
42 '''If no match was found,
43 return False
44 '''
45 return False
46
124 3 Math
47 '''
48 The main function that checks
49 if there exist three numbers in
50 a sorted list that add up
51 to a target number
52 '''
53 def has_three_summers ( numbers_list , goal ) :
54 '''If the length of the list is
55 less than 3, it is not possible
56 to find three numbers that
57 add up to the target
58 '''
59 i f len ( numbers_list ) < 3:
60 return False
61
62 # Iterate through the list one by one
63 for i in range ( len ( numbers_list ) ) :
64 '''Get the current number
65 from the list
66 '''
67 x = numbers_list [ i ]
68 '''Compute the new goal
69 by subtracting
70 '''
71 new_goal = goal − x
72
73 '''
74 Check if there exist two numbers
75 in the remaining list that add
76 up to the new target
77 '''
78 i f has_two_sum( numbers_list [ i +1:] , new_goal ) :
79 return True
80
81 '''
82 If no match was found,
83 return False
84 '''
85 return False
3.21 Perfect Power 125
Algorithm
Table 3.21 The expected outputs for certain inputs for determining if a number is a perfect power
n Expected output
2 False
27 True
729 True
1369 True
126 3 Math
Code 3.21 Python code for checking the perfect powers of the positive integers
1 def perfect_power (n ) :
2 '''
3 In Python, ** is used for the power operator
4 '''
5 power = 2
6
7 while True :
8 i f 2 ** power > n :
9 return False
10
11 # Find largest power using binary search approach
12 low = 2
13 high = n
14 while low <= high :
15 mid = (low + high ) / / 2
16 guess = mid ** power
17
18 i f guess == n :
19 return True
20 e l i f guess < n :
21 low = mid + 1
22 else :
23 high = mid − 1
24
25 # Increment power
26 power += 1
Table 3.22 The expected outputs for certain inputs for lunar multiplication
a, b Expected output
10, 21 110
170, 76 1760
45, 96 455
8, 7 7
Some examples of the input and expected output of the lunar multiplication problem
are illustrated in Table 3.22.
Algorithm
The algorithm for this problem is straightforward and simple. In one step, it performs
the multiplication between each two number, and then it adds the multiplied numbers
with considering their carries. The Python code for lunar multiplication is depicted
in Code 3.22.
Code 3.22 Python code for lunar multiplication
1 def multiply_by_lunar ( a , b ) :
2 '''
3 A function to add two
4 numbers in lunar addition
5 '''
6 def add_in_lunar (x , y ) :
7 # Convert x and y to strings, reverse them
8 '''
9 Because the calculation from
10 least significant digit is specified.
11 '''
12 x_reversed = rev (x)
13 y_reversed = rev (y)
14
15 # Initialize sum as an empty string
16 sum_reversed = ' '
17
18 '''Calculate maximum length of numbers
19 and perform addition
20 '''
21 max_len = max( len ( x_reversed ) , len ( y_reversed ) )
22
23 i = 0
24 while i < max_len :
128 3 Math
70 if d:
71 # Append remaining digits of d to numbers
72 numbers . append ( ' 0 ' * i + d)
73
74 '''Add numbers of each step using
75 the add_in_lunar function
76 '''
77 for num in numbers :
78 answer = add_in_lunar ( answer , num[:: −1])
79
80 return answer
81
82
83 # A function to reverse a number
84 def rev (x ) :
85 x_reversed= ' '
86 for i in range ( len ( str (x ) ) − 1 , −1, −1):
87 x_reversed += str (x ) [ i ]
88 return x_reversed
In the field of computer science, the Recamán sequence is a type of sequence that
exhibits a recurrence relation, whereby the computation of a new element is depen-
dent on the preceding elements. To illustrate, in order to derive the n-th term of the
Recamán sequence (where n = 1), the following steps are taken: It should be noted
that the elements of this sequence are determined by the recursive formula provided
in Eq. 3.7. The zeroth term, a0 , is always equal to zero. To calculate a1 , we find
that 0 − 1 = −1 < 0, thereby rejecting the second condition and proceeding with
the third condition, which gives a1 = 0 + 1. Write a function that takes a positive
integer n as input and returns the n-th term of the Recamán sequence.
⎧
⎨0 if n == 0
x = an−1 − 1 if an−1 − 1 > 0 and the number is not alr eady in sequence
⎩
an−1 + n else
(3.7)
For some inputs, the expected outputs are illustrated in Table 3.23.
130 3 Math
Table 3.23 The expected outputs for certain inputs for finding n-th term of Recaman sequence
n Expected output
17 25
83 72
919 756
632 308
Algorithm
To find the n-th term, the algorithm initializes the sequence with the first element,
and a set to keep track of used elements. It then iterates over the remaining elements
up to ‘n’, and for each element it calculates the next element using Eq. 3.7. If the next
element is negative or already used, it uses the alternative formula to calculate the
next element. The next element is then added to the sequence, and marked as used in
the set. Finally, the algorithm returns the n-th element of the sequence. The Python
code for computing the n-th term of the recaman sequence is depicted in Code 3.23.
Code 3.23 Python code for computing the n-th term of the recaman sequence
1 def Nth_term_of_recaman_sequence (n ) :
2 '''
3 Returns the nth item in the Recamán sequence
4 '''
5 # Initialize the sequence with the first element
6 seq = [0]
7 # Initialize a set to keep track of used elements
8 seen = {0}
9 # Iterate over the remaining elements up to n
10 for i in range (1 , n+1):
11 # Get the previous element of the sequence
12 prev = seq[−1]
13 '''Calculate the next element
14 using the following formula
15 '''
16 next = prev − i
17 '''
18 If the next element is negative
19 or already used, the alternative formula
20 '''
21 i f next < 0 or next in seen :
22 next = prev + i
23 # Add the next element to the sequence
24 seq . append ( next )
25 # Mark the next element as used in the set
3.24 Van Eck Sequence 131
Algorithm
The algorithm to determine the n-th term of the Van Eck sequence is presented below:
1. Initialize the sequence with the first term, which is 0.
2. Create an empty dictionary to store the index of each value in the sequence.
3. For each index i from 0 to n − 1
Table 3.24 The expected outputs for certain inputs for finding n-th term of Van Eck sequence
n Expected output
258 3
25 4
2 1
2089 0
132 3 Math
Table 3.25 The expected outputs for certain inputs for finding non-consecutive Fibonacci numbers
n Expected output
53 [34, 13, 5, 1]
25 [21, 3,1]
31 [21, 8, 2]
3009 [2584, 377, 34, 13, 1]
Algorithm
29 sum_of_fib_nums += num
30 i f sum_of_fib_nums == n :
31 return selected_fib_nums
The Fibonacci word is a sequence that resembles the ordinary Fibonacci sequence,
with the difference that instead of the sum of the two previous numbers, their con-
catenation is considered. The first term of this sequence is 0, and the second term is
01 (as a string). Each subsequent term is obtained by concatenating the two previous
terms. For example, the third term is obtained by concatenating the first and second
terms, which results in 010. Similarly, the fourth term is obtained by concatenat-
ing the second and third terms, which results in 01001, and so on. This challenge
requires a function that takes an input integer k and returns the k-th character of the
Fibonacci word, where the sequence is a string consisting of the characters 0 and
1. The function must be implemented to handle the desired inputs and provide the
expected outputs as illustrated in Table 3.26.
Algorithm
Table 3.26 The expected outputs for certain inputs for finding k-th term in Fibonacci word
k Expected output
65 0
170 0
98 1
2022 1
136 3 Math
Table 3.27 The expected outputs for certain inputs for finding the most point line on the two-
dimensional integer grid
k Expected output
[(4, 4), (6, 6), (3, 2), (1, 4)] 2
[(14, 4), (0, 0), (1, 2), (3, 0)] 2
[(3, 15), (1, 4), (2, 6), (8, 7), (3, 8)] 3
3.27 Finding the Most Point Line 137
Algorithm
The algorithm takes a list of 2D integer grid points as input and returns the maximum
number of points on a line passing through of the points. The algorithm first checks
if the length of the input list is less than 3, in which case it returns the length of the
list. Otherwise, it iterates through each pair of distinct points in the list, calculates
the slope of the line passing through those points, and keeps track of the frequency of
each slope using a dictionary. It also keeps track of the number of duplicate points.
Finally, it returns the maximum number of points on a line by adding the current
maximum number of points to the number of duplicates and comparing it to the
previous maximum. The Python code for the line with the most points is depicted in
Code 3.27.
Code 3.27 Python code for line with most points
1 def calculate_gcd ( a , b ) :
2 '''
3 Compute the greatest common
4 divisor of two integers a and b
5 '''
6 while b != 0:
7 a, b = b, a % b
8 return a
9
10 def count_points_on_line ( points ) :
11 n = len ( points )
12 '''
13 If there are less than three points,
14 they always form a line.
15 '''
16 i f n < 3:
17 return n
18
19 max_points_on_line = 0
20 i = 0
21 '''
22 Iterate through each point
23 in the list of points
24 '''
25 while i < n :
26 '''
27 Create a dictionary to keep track
28 of slopes and their frequency
29 '''
30 slope_count = {}
31 num_duplicates = 1
138 3 Math
32 cur_max_points_on_line = 0
33 j = i+1
34 # Compare with other points to calculate the slope
35 while j < n :
36 i f points [ i ] == points [ j ] :
37 num_duplicates += 1
38 else :
39 dx = points [ j ] [ 0 ] − points [ i ] [ 0 ]
40 dy = points [ j ] [ 1 ] − points [ i ] [ 1 ]
41 i f dx == 0:
42 slope = float ( ' i n f ' )
43 else :
44 gcd = calculate_gcd (dy , dx)
45 slope = (dy / / gcd , dx / / gcd )
46
47 '''
48 Add the slope to the dictionary
49 or increment its frequency
50 '''
51 slope_count [ slope ] = \
52 slope_count . get ( slope , 0) + 1
53
54 '''
55 Update the maximum number of points
56 on a line with the current slope
57 '''
58 cur_max_points_on_line = \
59 max( cur_max_points_on_line ,
60 slope_count [ slope ] )
61
62 j += 1
63
64 '''
65 Update the overall maximum number of points
66 on a line considering current point
67 '''
68 max_points_on_line =\
69 max( max_points_on_line ,
70 cur_max_points_on_line + num_duplicates )
71 i += 1
72
73 return max_points_on_line
3.28 Is a Balanced Centrifuge 139
Scientists use centrifuges to test tubes, but it is essential to balance the tubes in the
centrifuge to avoid disrupting its performance or causing serious damage due to its
high speed. The balancing can be achieved by placing the tubes in a manner such that
they either face each other or form a regular pattern. For example, in Fig. 3.3, part A
shows a centrifuge with six different holes, while part B shows four tubes placed in
four of the holes. As can be seen in part B, the test tubes are balanced, with the two
tubes on the left and right facing each other. For certain input values, the expected
outputs are listed in Table 3.28.
The objective of this challenge is to determine whether a given situation is bal-
anced, given the values of n and k. A function is required that takes as input the
number of holes and tubes, representing n and k respectively, and returns true if the
situation is balanced, or false otherwise.
Algorithm
Given n and k, the first step involves determining the prime factors of n and storing
them in a list L. Subsequently, it is necessary to verify whether it is feasible to obtain
both n − k and k using the prime factors in L. For example, consider the case where
A) Centrifuge with six holes, n=6 B) Centrifuge with six holes and 4 tube (red ones),
n=6, k=4
Table 3.28 The expected outputs for certain inputs determining if a centrifuge is balanced or not
n, k Expected output
76, 19 True
23, 3 False
113, 18 False
60, 2 True
140 3 Math
n = 6 and k = 3. The list of prime factors for n is [2, 3]. As both k and n − k can
be expressed using the prime factors in L. Specifically, k = 3 is included in L, and
n − k = 6 − 3 = 3 is also present in L, indicating a balanced situation for n = 6 and
k = 3. An additional example involves the values n = 15 and k = 8, whereby the
list of prime factors is [5, 3]. While it is possible to obtain k by adding 5 and 3, it is
not possible to obtain n − k, which in this case is 7, using the numbers in the list.
Consequently, the function returns false.
To solve the problem, two algorithms are being considered. The first algorithm is
used to determine the prime factors of n, while the second algorithm is used to verify
whether n and n − k can be created using the prime factors obtained from the first
algorithm.
An empty list to store prime factors is created. The first prime number is equal to
2. As long as n is greater than 1, n is divided by 2. If the remainder is zero and
the number was not added to the considered list, we add it to the list. In each step,
n is updated with the quotient. If n is no longer divisible by 2, the next prime is
considered, and this process is repeated until n < 1.
It takes a positive integer ‘n’ as input and returns a list of prime factors of ‘n’.
The step-by-step explanation of the algorithm is outlined below.
1. An empty list called ‘primes’ is initialized to store the prime factors.
2. A variable ‘i’ is initialized to 2, which is the first prime number.
3. A while loop is used to check if the number ‘n’ is greater than 1.
4. Inside the loop, it checks if ‘n’ is divisible by ‘i’. If ‘n’ is divisible by ‘i’, it means
that ‘i’ is a factor of ‘n’.
5. If ‘i’ is a prime factor of ‘n’ and is not already in the ‘primes’ list, it is added to
the list.
6. ‘n’ is then divided by ‘i’, so that we can continue to check if ‘i’ is a prime factor
of the remaining value of ‘n’.
7. If ‘i’ is not a prime factor of ‘n’, ‘i’ is incremented by 1 and the loop continues to
the next iteration.
8. The loop continues until ‘n’ is less than or equal to 1.
9. Finally, the list of ‘primes’ containing all the prime factors of ‘n’ is returned as
the output of the algorithm.
Coin Change
The coin change algorithm is used to determine whether a given number can be
expressed as a combination of values from a specified list. This algorithm takes
as input a number and an array, and checks whether the number can be formed
using elements of the given list. The idea to solve this problem is to use dynamic
3.28 Is a Balanced Centrifuge 141
This chapter talks about 21 number-based problems. These challenges are explained
with some examples and then programmed in Python. The problems are listed below:
© The Author(s), under exclusive license to Springer Nature Switzerland AG 2024 143
H. Izadkhah and R. Behzadidoost, Challenging Programming in Python: A Problem
Solving Perspective, https://doi.org/10.1007/978-3-031-39999-2_4
144 4 Number
A domino tile can be represented by a two-tuple (x, y), where x and y are positive
integers. The objective of this challenge is to identify a domino cycle from a given
set of tiles. For example, [(5, 2), (2, 3), (3, 4), (4, 5)] has a domino cycle. The first
domino tile (5, 2) is a connection with (2, 3); 2 → 2. The domino tile (2, 3) is a
connection with (3, 4); 3 → 3, and the other are: 4 → 4, 5 → 5. Write a function that
as input, takes a list of dominoes, and returns true if there is a domino cycle, otherwise
returns false. For some inputs, the expected outputs are illustrated in Table 4.21.
Algorithm
The algorithm must check if y and x of the two compared tuples are not equal in
each step. If they are not equal, it must return False; otherwise, it must return True.
The Python code for determining the domino cycle is depicted in Code 4.2.
Code 4.2 Python code for determining the domino cycle
1 def Is_a_domino_cycle( t i l e s ) :
2 index = 0
3 while index < len( t i l e s ) :
4 # The comparing condition
5 i f t i l e s [index][0] != t i l e s [( index−1)%len( t i l e s )][1]:
6 ’’’
7 If the condition is not met only once,
8 false is returned.
Table 4.2 The expected outputs for certain inputs for checking if there is a domino cycle
Tiles Expected output
[(5, 2), (2, 3), (3, 4), (4, 5)] True
[(3, 4), (4, 2), (2, 3), (3, 1), (4, 2)] False
[(3, 4), (4, 2), (2, 3), (3, 1), (4, 2), (2, 4), (6, 3), False
(3, 2)]
[(6, 4), (4, 5), (5, 6)] True
146 4 Number
9 ’’’
10 return False
11 index += 1
12 return True
In this challenge, a string of digits is given and it is guaranteed that the digits are
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, and the task is to find the increasing digits. For instance,
consider 457990, which has the increasing digits 4, 5, 7, 9 and 90. Write a function
that as input, takes a string containing digits, and returns the list of increasing digits.
For some inputs, the expected outputs are illustrated in Table 4.3.
Algorithm
The algorithm in two blocks checks the increasing digits. At first, an empty string
concatnumber s is defined, and it is set b = 1. If b = 1, it enters the first block,
and if b = 0, it enters the second block. For each digit of the given string, in the
first block, with the linear search if the next number was greater than the previous
number and b = 1, then the next number is appended into an array storage and
updates the previous number. In the second block, if the comparison was not met in
the first block, then b = 0, and make concatenation for the current number and its
next, and put it in concatnumber s. If concatnumber s was greater than the previous
number, then store it into storage, and make empty concatnumber s. As long as a
concatenation of the next numbers is less than or equal to the previous number the
concatenation is repeated for the next numbers. When b = 0 it never can enter the
first block, because no longer single digits are greater than previous numbers, and
entering the first block is meaningless. The Python code for extracting the increasing
digits is depicted in Code 4.3.
Algorithm
At first, the algorithm must split the string by ‘,’. In the next step, it must separate
the single numbers from the intervals. The single numbers are stored in a list, and
using a for loop iterates through the start and end of the interval, and each time the
included numbers into the range are stored in a list. Outlined below are the detailed
steps involved in the algorithm
1. It takes the string inter vals as input.
2. Check if inter vals is empty. If it is, return an empty list.
3. Create an empty list called r esult to store the expanded integers.
4. Split the input string into individual intervals using the comma as the delimiter
and store them in a list called inter vals_list.
5. For each interval in inter vals_list, check if it contains only one number (i.e.,
if there is no dash ‘-’). If so, convert the number to an integer using int() and
append it to the r esult list.
6. If the interval contains a range of numbers (i.e., if there is a dash ‘-’), split the
interval by the dash and convert the star t and end of the range to integers using
int ().
7. Generate all the numbers between the star t and end using the range() function
and add them to the result list using the extend() method.
8. Once all the intervals have been processed, return the final r esult list containing
all the expanded integers.
The Python code for expanding the intervals is depicted in Code 4.4.
Code 4.4 Python code for expanding the integer intervals
1 def Expanding_Integer_Intervals ( intervals ) :
2 ’’’
3 If there are no given numbers,
4 then returns an empty list
5 ’’’
6 i f intervals == ’ ’ :
7 return []
8 ’’’
9 create an empty list to store
10 the expanded integers
11 ’’’
12 result = []
13 ’’’
14 split the input string
15 into individual intervals
16 ’’’
17 intervals_list = intervals . s p l i t ( ’ , ’ )
18
19 for interval in intervals_list :
20 ’’’
21 Check if the interval
22 only contains one number
23 ’’’
24 i f ’−’ not in interval :
25 ’’’
26 convert it to an integer
27 and add to the result list
28 ’’’
29 result .append( int ( interval ))
30
31 else :
32 # If the interval contains a range of numbers
33 # extract the start and end of the range
34 start_end = interval . s p l i t ( ’−’ )
35 s t a r t = int ( start_end [0])
36 end = int ( start_end [1])
37 ’’’
38 generate all numbers between start and
39 end, and add to result list
40 ’’’
41 ’’’
42 range(x,y)---range(x,y-1),
150 4 Number
This function is the inverse of the previous problem. Write a function that as input
takes a list of numbers and returns a string of digits and intervals in the form ‘first-last’
such that are comma separated. For some inputs, the expected outputs are illustrated
in Table 4.5.
Algorithm
The algorithm to solve this challenge is rule-based. In fact, it iterates over a list of
integers and identifying ranges of consecutive integers.
1. It takes a list of positive integer numbers as input.
2. Initialize two variables called ‘start’ and ‘end’ to None.
3. For each integer ‘item’ in the input list of integers ‘items’, do the following:
a. If ‘start’ is None, set both ‘start’ and ‘end’ to ‘item’.
b. If ‘item’ is equal to ‘end + 1’, update ‘end’ to ‘item’.
c. If ‘item’ is not adjacent to the previous ‘end’, add the current range to ‘ranges’,
where If ‘start’ is equal to ‘end’, append ‘str(start)’ to the ‘ranges’ list.
d. Otherwise, append ‘str(start)’ + ‘−’ + ‘str(end)’ to the ‘ranges’ list.
e. Then, start a new range by setting both ‘start’ and ‘end’ to ‘item’.
4. If ‘start’ is not None, add the final range to ‘ranges’ using the same logic as the
previous step.
5. Join the ranges with commas and return the resulting string.
The Python code for collapsing the numbers is depicted in Code 4.5.
Code 4.5 Python code for collapsing the numbers
1 def collapse_integer_intervals (items ) :
2 ranges = []
3 s t a r t = end = None
4
5 for item in items :
6 i f s t a r t is None:
7 # Start a new range
8 s t a r t = end = item
9 e l i f item == end + 1:
10 # Expand the current range
11 end = item
12 else :
13 # Add the current range to the list
14 i f s t a r t == end:
15 ranges .append( str ( s t a r t ))
16 else :
17 ranges .append( str ( s t a r t ) + ’−’ + str (end))
18
19 # Start a new range
20 s t a r t = end = item
21
22 # Add the final range to the list
23 i f s t a r t is not None:
24 i f s t a r t == end:
25 ranges .append( str ( s t a r t ))
26 else :
27 ranges .append( str ( s t a r t ) + ’−’ + str (end))
28
29 # Join the ranges with commas
30 return " , " . join (ranges)
Consider a dice that have six sides with pips from one to six such that, there are
eight corners, and in each corner, there are three visible numbers. From left or right,
the dice have a different view. For instance, consider Fig. 4.1, part b, from the left-
152 4 Number
(a) Right-handed
(b) Left-handed
Table 4.6 The expected n Expected output
outputs for certain inputs to
determine if a dice is (4, 2, 1) True
left-handed (6, 3, 2) True
(6, 5, 4) False
handed (clockwise) the reading is done each time. For the first time, 1, 2, 3 is read;
the next number after 1 is 2, so reading from 2 is considered, so 2, 3, 1; the next
number after 2 is 3, so reading from 3 is considered, so 3, 1, 2. Therefore, with
views of left-handed for the corner 1, 2, 3, there are three permutations of 1, 2, 3,
2, 3, 1, and 3, 1, 2. There are eight different corners for left-handed and each with
three numbers, so 8 ∗ 3 = 24. Likewise, the same is true for right-handed. In total
there are 24+24= 48 permutations in left-handed and right-handed. Write a Python
function that as input, takes a corner and determines whether is left-handed or right-
handed; if it is left-handed, returns true, otherwise, returns false. For some inputs,
the expected outputs are illustrated in Table 4.6.
Algorithm
The Python code for determining the left-handed or right-handed is depicted in Code
4.6.
Code 4.6 Python code for determining the left-handed or right-handed
1 def is_left_handed_dice ( pips ) :
2 Left_Handed = [(1 , 2, 3) , (3 , 1, 2) , (2 , 3, 1) ,
3 (1 , 4, 2) , (2 , 1, 4) , (6 , 3, 2) ,
4 (4 , 2, 1) , (5 , 6, 4) , (4 , 5, 6) , (6 , 4, 5) ,
5 (3 , 6, 5) , (5 , 3, 6) ,
6 (6 , 5, 3) , (5 , 4, 1) , (1 , 5, 4) , (4 , 1, 5) ,
7 (2 , 4, 6) , (6 , 2, 4) ,
8 (4 , 6, 2) , (1 , 3, 5) , (5 , 1, 3) , (3 , 5, 1) ,
9 (2 , 6, 3) , (3 , 2, 6)]
10
11 i f pips in Left_Handed:
12 return True
13 else :
14 return False
Suppose an individual is walking on the street and comes across two taxis. One
has the number 1729, while the other has the number 6666. It is evident that the
number 6666 is more easily remembered due to the repeating sequence of digits. The
human mind tends to recall numbers that have a repeating sequence more quickly.
For instance, people tend to remember hours like 12 : 12 faster than ones without
a repeating sequence, such as 10 : 23. This challenge aims to draw attention to
sequences of numbers that have repeated digits. A score is assigned based on the
number of repeated digits in the sequence. If the sequence has two repeated digits,
the score is one. If it has three repeated digits, the score is ten. If it has four repeated
digits, the score is one hundred, and so on. Furthermore, if the sequence ends with
a repeating digit, the score is doubled. For example, 12333 is a number that has
repeated numbers, and its lowest number ends with a repeated number. The scoring
measure is represented by Eq. 4.1.
10(k−2) i f ther e is any r epeated sequence
scor e = (4.1)
2 × 10(k−2) i f the lowest number is in r epeated sequence
Write a function that as input, takes a positive integer n, and if visits a repeated
sequence score it with 10(k−2) each time, or if n ends with the repeating sequence,
score it with 2 × 10(k−2) . For some inputs, the expected outputs are illustrated in
Table 4.7.
154 4 Number
Algorithm
The algorithm takes integer n and iterates over each digit in the input number, and
checks whether the current digit is the same as the previous digit. If it is the same, the
algorithm increments a counter for the number of repeated digits. If it is different,
the algorithm scores the count of repeated digits so far and resets the counter for the
new digit. Finally, the algorithm scores any remaining repeated digits at the end of
the number. The algorithm has the following steps.
1. It takes an integer n.
2. Initialize a variable called scor e to zero.
3. Initialize a variable called count to one.
4. Initialize a variable called pr ev_digit to None.
5. Convert the integer n to a string and iterate over each digit in the string:
a. If the current digit is the same as the previous digit ( pr ev_digit), increment
the count variable.
b. If the current digit is different from the previous digit:
c. If count is greater than 1, add 10(count−2) to the scor e variable. This gives a
score based on the number of repeated digits so far.
d. Reset the count variable to 1 for the new digit.
e. Set pr ev_digit to the current digit for the next iteration.
6. If the final digit(s) are repeated, add 2 × 10(count−2) to the scor e variable. This
gives a bonus score for the final repeated digits.
7. Return scor e.
The Python code for assigning bonus to repeated positive integers is depicted in
Code 4.7.
Code 4.7 Python code for assigning bonus to repeated positive integers
1 def duplicate_digit_score (n) :
2 score = 0
3 # initialize previous digit to None
4 count = 1
5 prev_digit = None
6
7 ’’’
8 iterate over each digit
4.7 Bonus to Repeated Numbers 155
9 in n
10 ’’’
11 for digit in str (n) :
12 ’’’
13 check if the current digit is
14 the same as the previous digit
15 ’’’
16 i f prev_digit == digit :
17 # increment the count of repeated digits
18 count += 1
19 else :
20 ’’’
21 if the previous digit was also repeated,
22 score the count
23 ’’’
24 i f count > 1:
25 # score the count of repeated digits
26 score += 10 ** (count − 2)
27 # reset the count for the new digit
28 count = 1
29 ’’’
30 update the previous digit
31 for the next iteration
32 ’’’
33 prev_digit = digit
34
35 ’’’
36 score any remaining repeated digits
37 at the end of the number
38 ’’’
39 i f count > 1:
40 ’’’
41 double the score for the
42 last repeated digit
43 ’’’
44 score += 2 * 10 ** (count − 2)
45 return score
156 4 Number
Let there be an array that is filled with positive integer numbers. In this challenge,
for each number, it is aimed to find the first smallest number in the array, and if
there is no smallest number, the number is to be unchanged. For example, consider
array = [2, 77, 13, 1]. The first number is 2, and on the left of 2, there is no number,
so the right part is considered. In the right, 1 is minimum, so [2, 77, 13, 1] → [1].
The next number is 77. On the left of 2, there is 2, and on the right part 1 is minimum,
but 2 is the first minimum, so [2, 77, 13, 1] → [1, 2]. The next number is 13, and the
first minimum is 1 [2, 77, 13, 1] → [1, 2, 1]. The next number is 1, and no number
is smaller than 1, the current element, which 1 is considered, so [1, 2, 1, 1]. Write a
function that as input, takes a filled array with the integer numbers, and returns an
array of numbers where each element in the array is the nearest smaller number to
the corresponding element in the input array. For some inputs, the expected outputs
are illustrated in Table 4.8.
Algorithm
The algorithm uses nested loops to iterate over each element in the input array and
its surrounding elements. The algorithm finds the nearest smaller element for each
element in the input array by comparing the element with its adjacent elements to
the left and right of it. If either the left or right element is smaller than the current
element, the smallest of the two elements is considered. It also handles the cases
where the current element has no left or right element by setting the left or right
element to the current element itself. The Python code for computing the nearest first
smaller number is depicted in Code 4.8.
Code 4.8 Python code for computing the nearest first smaller number
1 def Nearest_first_smaller_number( array ) :
2 n = len( array )
3 nearest_smaller = []
4
5 # Iterate over each element in the input array
6 for x, current_element in enumerate( array ) :
7
8 ’’’
4.8 Nearest First Smaller Number 157
54 else :
55 nearest_smaller .append(current_element )
56
57 return nearest_smaller
In this challenge, a list of objects is given and the task is to identify and return
the object that is preceded by at least k number of smaller objects. In case such an
item does not exist, the function will return a value of None. For example, consider
items = [2, 1, 9, 14], and k = 2. Which number is preceded by at least k smaller
numbers? As 9 is preceded by 1 and 2, 9 is the answer. If the items = [4, 2, 1, 9, 14]
and k = 2, again the answer is 9, as the at least preceding is wanted. For the sec-
ond example, consider [‘cobol , ‘r uby , ‘c + + , ‘ python , ‘c , ‘ php ], and k = 2.
Which string is preceded by at least k smaller numbers? Firstly, the length of each
string is taken. The same operations as the previous example are done. The answer
for the second one is ‘ python , as its length is six and preceded by ‘c + + , ‘cobol ,
and ‘r uby . For some inputs, the expected outputs are illustrated in Table 4.9.
Algorithm
The algorithm goes through each item in the items list and checks if there are at least
k smaller items before it. To do this, the algorithm creates a sublist of all items before
the current item that are smaller than it. This is done using list comprehension. Once
the sublist is created, its length is checked against k. If the length is greater than or
equal to k, the algorithm returns the current item as the first item in the original list
that has at least k smaller items before it. If no such item exists, the algorithm returns
None. The Python code for computing first preceding number by smaller numbers
is depicted in Code 4.9.
Code 4.9 Python code for computing first preceding number by smaller numbers
1 def first_preceded_by_k_smaller_number(items , k=1):
2 ’’’
3 Loop through each item in the list
4 ‘items‘ along with its index.
4.10 n-th Term of Calkin Wilf 159
5 ’’’
6 for i , current_number in enumerate(items ) :
7
8 ’’’
9 Create a list of all items before the current
10 item that are smaller than it.
11 ’’’
12 smaller_numbers = \
13 [n for n in items [ : i ] i f n < current_number]
14
15 ’’’
16 If there are at least ‘k‘ smaller items before
17 the current item, return the current item.
18 ’’’
19 i f len(smaller_numbers) >= k:
20 return current_number
21
22 ’’’
23 If there is no item that satisfies
24 the condition, return None.
25 ’’’
26 return None
The Calkin-Wilf tree is a rooted binary tree whose vertices are in one-to-one cor-
respondence with the positive rational numbers. The root of the tree corresponds
to the number 1, and for any rational number a/b, its left child corresponds to the
number a/(a+b) and its right child corresponds to the number (a+b)/b. Each rational
number appears exactly once in the tree. When performing a level-order traversal of
the Calkin-Wilf tree, a sequence of rational numbers is generated, which is known
as the Calkin-Wilf sequence. We would like to define a function that takes a positive
integer n as input and returns the n-th term of the Calkin-Wilf sequence, which is a
rational number. For example, consider the following example. If n = 10, the output
3
is 3+2 . The process of reaching to the answer is described below. 11 , 1+1
1
, 1+1
1
1
, 2+1 ,
2+1 2 2+1 1 1+3 3
2
, 2+1 , 1 , 1+3 , 3 , 3+2 . For some inputs, the expected outputs are illustrated
in Table 4.10.
160 4 Number
Algorithm
In this challenge, an array of positive integer numbers is given, and the task is to
find the reverse of the ascending subarrays. Each sub-list must be strictly ascend-
ing. For example, for [5, 7, 220, 33, 2, 6, 8, 1, 45] as input, output the reverse of the
ascending subarrays: The subarrays are: [5, 7, 220], [33], [2, 6, 8], [1, 45], and in the
next step, the sub-lists are reversed: [220, 7, 5, ], [33], [8, 6, ], [45, 1]. The reversed
subarrays in their original order are merged. Hence, [5, 7, 220, 33, 2, 6, 8, 1, 45] →
[220, 7, 5, 33, 8, 6, 2, 45, 1]. For some inputs, the expected outputs are illustrated in
Table 4.11.
Algorithm
The algorithm use two-pointer technique, where ‘i’ pointer is used to point to the
start of the sublist, and the ‘j’ pointer is used to find the end of the ascending sub-
list. After finding an ascending subarray, the program uses slicing and reversing to
reverse the sublist elements and then appends them to the final result list. Finally,
it sets the new starting index ‘i’ for the next subarray. The ‘i’ pointer is then incre-
mented to the next sublist, and the process is repeated until the end of the list is
reached. The Python code to reverse the ascending sub-lists is depicted in Code
r ever se_ascending_subarrays.
Code 4.11 Python code to reverse the ascending sub-lists
1 def reverse_ascending_subarrays (List_Numbers ) :
2 ’’’
3 create an empty list to store
4 the ascending sublists
5 ’’’
6 ascending_subarray = []
7 # set the starting index to 0
8 i = 0
9 # loop through the list
10 while i < len(List_Numbers ) :
11 # set j to the current index
12 j = i
13 # check if there is an ascending order
14 while j < len(List_Numbers) − 1 \
15 and List_Numbers[ j ] < List_Numbers[ j +1]:
16 j += 1
17 ’’’
18 reverse and add the sublist
19 to the result list
20 ’’’
21 ascending_subarray . extend \
22 (List_Numbers[ i : j +1][::−1])
23 # set the starting index for the next subarray
24 i = j + 1
25 return ascending_subarray
Large integer powers can make calculations complicated in terms of both time and
memory. The objective of this challenge is to find the smallest positive integers ‘x’
and ‘y’ such that a x and b y are within a certain tolerance of each other. In this
context, ‘tolerance’ specifies the maximum acceptable difference between the two
integer powers of ‘a’ and ‘b’. Write a function that takes ‘a’, ‘b’, and ‘tolerance’
as input and returns the smallest positive integers ‘x’ and ‘y’. For some inputs, the
expected outputs are illustrated in Table 4.12.
Algorithm
To solve this challenge, we utilize a greedy approach. The algorithm tries to find the
smallest pair of positive integers x and y that satisfy the tolerance. It does this by
iteratively increasing the values of x and y while also increasing the powers of a and
b using repeated multiplication until the difference between the powers is less than
or equal to a given tolerance. This approach may not always guarantee the optimal
solution but it finds a reasonably good solution in a reasonably efficient way.
1. It takes integer number of a and b.
2. Set x and y to 1.
3. Set a_ pow and b_ pow to a and b, respectively.
4. Enter an infinite loop:
a. If a_ pow is greater than b_ pow, check if the tolerance is less than or equal
to b_ pow divided by the difference between a_ pow and b_ pow.
b. If it is, return x and y.
c. Otherwise, increment y by 1 and multiply b_ pow by b.
d. If a_ pow is less than b_ pow, check if the tolerance is less than or equal to
a_ pow divided by the difference between b_ pow and a_ pow.
e. If it is, return x and y.
f. Otherwise, increment x by 1 and multiply a_ pow by a. If a_ pow and b_ pow
are equal, return x and y.
The Python code to compute and return the smallest integer powers is depicted in
Code 4.12.
Code 4.12 Python code to compute and return the smallest powers
1 def smallest_integer_powers (a , b, tolerance=100):
2 x, y = 1, 1
3 a_pow, b_pow = a , b
4
5 while True:
6 i f a_pow > b_pow:
7 i f tolerance <= b_pow / (a_pow − b_pow) :
8 return x, y
9 y += 1
10 b_pow *= b
11 e l i f a_pow < b_pow:
12 i f tolerance <= a_pow / (b_pow − a_pow) :
13 return x, y
14 x += 1
15 a_pow *= a
16 else :
17 return x, y
4.13 Sorting Cycles of a Graph 165
A cycle is a path that starts and ends at the same vertex. Consider a given array G,
which is filled with positive integer numbers. Each number in G is the vertex of
a graph. In this challenge, the task is to find the cycles G and sort them in some
orders. For example, let G = [2, 4, 6, 5, 3, 1, 0] be as input, find the cycles such that
in each cycle, the greatest number be the first vertex in the cycle, and the vertices
that their positions or indexes are after the greatest number position, are inserted
after the greatest number position, while the vertices that their positions are before
the greatest number position are inserted after the position of the greatest number
and the vertices that their positions are after the greatest number position; after it, all
cycles in ascending order must be sorted. The first vertex G is 2, which number is in
index 2? As the index in Python starts from zero, so the number is 6. In the next step,
which number is in the index 6? The number is 0. In the next step, which number is
in index 0? The number is 0, so a cycle is found, 2→ 6→ 0 → 2. In this step, the
first cycle is inserted, C = [[2, 6, 0]]. The first vertex that is not visited is 4, so it is
considered the first vertex of the cycle. In the next step, which number is in index
4? The number is 3. In the next step, which number is in index 3? The number is
5. In the next step, which number is in index 5? The number is 1. In the next step,
which number is in index 1? The number is 4. So, a cycle is found, 4→ 3→ 5 → 1
→ 4. In this step, the second cycle is inserted, C = [[2, 6, 0], [4, 3, 5, 1]]. There is
no remaining vertex in G, so the sorting process is to be performed. For [2, 6, 0], the
greatest number (vertex) is 6, so [2, 6, 0] → [6], 0 is after 6, so [6] → [6, 0], and 2
is before 6, so [6, 0] → [6, 0, 2]. The updated cycles are C = [[6, 0, 2], [4, 3, 5, 1]].
For the second cycle [4, 3, 5, 1], the greatest number is 5, so [4, 3, 5, 1] → [5]. The
next one after index 5 is 1, so 1 is inserted after 5 and previous ones after the index
5 are 4 and 3, so 4 and 3 are appended after 5 and 1, respectively. Hence the cycles
are C = [[6, 0, 2], [5, 1, 4, 3]]. In the next step, the cycles in ascending order are
sorted, so C = [[6, 0, 2], [5, 1, 4, 3]] → C = [[5, 1, 4, 3], [6, 0, 2]]. In the last step,
the nested array is flatted; C = [5, 1, 4, 3, 6, 0, 2]. Write a function that as input,
takes array G, and returns the sorted cycles. For some inputs, the expected outputs
are illustrated in Table 4.13.
Algorithm
30 current_cycle = [ s t a r t ]
31 visited .add( s t a r t )
32 neighbor = g[ s t a r t ]
33 while neighbor != s t a r t :
34 current_cycle .append(neighbor)
35 visited .add(neighbor)
36 neighbor = g[neighbor]
37 cycles .append( current_cycle )
38 return cycles
39
40 ’’’
41 Sort a list of cycles
42 based on a specific criterion
43 ’’’
44 def sort_cycles ( cycles ) :
45 sorted_cycles = []
46 for cycle in cycles :
47 i f len( cycle ) == 1:
48 sorted_cycles .append( cycle )
49 else :
50 highest = max( cycle )
51 highest_index = cycle . index( highest )
52 sorted_cycle = \
53 cycle [highest_index:]+cycle [ : highest_index ]
54 sorted_cycles .append( sorted_cycle )
55 sorted_cycles = insertion_sort ( sorted_cycles )
56 flat_sorted_cycles = \
57 [ vertex for cycle
58 in sorted_cycles for vertex in cycle ]
59 return flat_sorted_cycles
60
61 # Call the find_cycles and sort_cycles functions
62 cycles = find_cycles (graph)
63 flat_cycles = sort_cycles ( cycles )
64
65 # Return the flattened list of cycles
66 return flat_cycles
We know that in any base r , the digits are from 0 to r − 1. Let n = 2201, and
convert it to base 10. 2 × 30 +2 × 31 +0+1 × 33 = 35. The calculations performed,
were the normal way to convert from the base 3 to 10. There is another way to convert
168 4 Number
Algorithm
The algorithm takes a positive integer n as input. To obtain the coefficient, the algo-
rithm computes the remainder of n divided by 3, denoted Remainder . It then con-
siders the integer part of (n + 1)/3 and computes Remainder again. This process is
repeated until n is not equal to 0. In the next step, let p be the corresponding position
of each coefficient. For each element i in Remainder, the algorithm checks if i is
equal to 1. If i is equal to 1, the algorithm computes 1 multiplied by 3 raised to the
power of p. If i is equal to −1, the algorithm computes −1 multiplied by 3 raised to
the power of p. If i is equal to 0, no computation is performed. The Python code for
balanced ternary is depicted in Code 4.14.
Code 4.14 Python code for balanced ternary
1 def Obtaining_Numbers_in_Balanced_Ternary_System(n) :
2 remainders = ""
3 while n!=0:
4 # Obtaining the remainder part
5 ’’’
6 The Coefficients are 0 ,1 and −1,
7 but −1 is two character one for − and another
8 for 1. Hence, 2 instead −1 is considered
9 ’’’
10 remainders = remainders+"012"[n % 3]
11 ’’’
12 [n % 3] generates a digit 0 or 1 or 2,
4.15 Is Strictly Ascending 169
The objective of this challenge is to check whether the elements of a given list are
arranged in strictly ascending order. It is important to note that a list with duplicate
numbers cannot be considered as strictly ascending. To implement the solution,
please keep the following points in mind:
170 4 Number
Algorithm
The algorithm implemented in this problem involves each number in the input list
checking itself against the previous number. If any number is found to be less than
or equal to its preceding numbers, the algorithm will return false, indicating that the
list is not strictly ascending. Conversely, if all numbers are strictly greater than their
predecessors, the algorithm will return true, indicating that the list is indeed in strictly
ascending order. The Python code for the strictly ascending problem is depicted in
Code 4.15.
Code 4.15 Python code for the strictly ascending problem
1 def Is_Strictly_Ascending(items ) :
2 ’’’
3 Simply check each number to previous number
4 ’’’
5 ’’’
6 Considering the first number
7 as previous number
8 ’’’
9 previous=items[0]
10 templist =[]
11 for num in items :
12 # If the condition was met, return false
13 i f num < previous :
14 return False
15 # If the condition was met, return false
16 i f num in templist :
17 return False
18 #updating the previous number
19 previous=num
4.16 Priority Sorting 171
20 ’’’
21 If item is in templist,
22 there is duplicate
23 number and false is returned
24 ’’’
25 templist .append(num)
26 return True
In this challenge, you are given a list and a set, both of which contain positive and
negative integers. Your task is to create a function that takes these two data structures
as input and returns a sorted list that prioritizes the elements from the set. Specifically,
the function should first identify the elements that are present in both the list and the
set, and append them to a new list in ascending order. Then, it should append the
remaining elements from the list to the same list, and sort the final list in ascending
order. Write a function that as input, takes a list and a set, and returns a sorted list
such the set element are to be in priority. For some inputs, the expected outputs are
illustrated in Table 4.16.
Algorithm
The algorithm first identifies the minimum element in the input list and checks if
it is present in the set. If it is, the algorithm appends the minimum element to the
output list as many times as it appears in the input list, removes all occurrences of
the minimum element from the input list, and removes the minimum element from
the set to avoid duplicates. This process is repeated for all elements in the set, which
ensures that the output list is sorted based on the priority set by the elements in the
set. After all the elements in the set have been processed, any remaining elements in
the input list are sorted and appended to the output list. The Python code for priority
sort is depicted in Code 4.16.
Code 4.16 Python code for priority sort
1 def priority_sort ( list , set ) :
2 ’’’
3 Sorts the input list in a specific
4 way based on the elements in the set.
5 If the list is empty, returns an empty list.
6 ’’’
7
8 # If the list is empty, return an empty list.
9 i f not l i s t :
10 return l i s t
11
12 # Create an empty list to store the sorted elements.
13 sorted_list = []
14
15 ’’’Create a range object that goes
16 from 0 to the length of the set.
17 ’’’
18 iterate_count = range(len( set ))
19
20 # Loop through the range object.
21 for i in iterate_count :
22 ’’’Check if the minimum element in
23 the set is also in the input list.
24 ’’’
25 i f min( set ) in l i s t :
26 ’’’
27 If it is, loop through the input list
28 and append the minimum element to sorted_list
29 ’’’
30 # as many times as it appears in input list.
31 for k in range( l i s t . count(min( set ) ) ) :
32 sorted_list .append(min( set ))
33 ’’’Remove all occurrences of the minimum
34 element from the input list.
35 ’’’
36 l i s t .remove(min( set ))
37 ’’’
38 Remove the minimum element from
39 the set to avoid duplicates.
4.17 Sorting Positives, Keep Negatives 173
40 ’’’
41 set .remove(min( set ))
42 else :
43 ’’’
44 If the minimum element
45 is not in the input list,
46 simply remove it from the set.
47 ’’’
48 set .remove(min( set ))
49
50 ’’’
51 Create a range object that goes from 0
52 to the length of the input list.
53 ’’’
54 iterate_count = range(len( l i s t ))
55
56 # Loop through the range object.
57 for i in iterate_count :
58 # Find the minimum element in the input list.
59 min_elem = min( l i s t )
60 # Append the minimum element to sorted_list.
61 sorted_list .append(min_elem)
62 # Remove the minimum element from the input list.
63 l i s t .remove(min_elem)
64
65 # Return the sorted list.
66 return sorted_list
In this challenge, the task is to sort the positive integer number and keep the order of
negative integer numbers. Write a function that as input, takes an array of positive and
negative numbers, and returns the array with the same length such the positive ones
are sorted, while the order of negative ones is kept. For some inputs, the expected
outputs are illustrated in Table 4.17.
Algorithm
Bubble sort is used to sort the positive numbers in the input array in ascending order,
while keeping the negative numbers in their original positions. The dictionary is
used to keep track of the indices and values of the negative numbers before they are
174 4 Number
removed from the array. After the positive numbers are sorted, the negative numbers
are inserted back into their original positions using the indices stored in the dictionary.
The Python code to sort positive numbers and keep negatives is depicted in Code
4.17.
Code 4.17 Python code to sort positives numbers and keep negatives
1 def sort_positives_keep_negatives ( array ) :
2 # Sorting by bubble sort
3 def bubblesort ( array : l i s t ) :
4 for i in range(len( array ) ) :
5 flag = True
6 # Iterate over array
7 for j in range(len( array ) − i − 1):
8 ’’’
9 Compare two adjcent numbers
10 and swap if needed
11 ’’’
12 i f array [ j ] > array [ j + 1]:
13 array [ j ] , array [ j + 1] = \
14 array [ j + 1] , array [ j ]
15 flag = False
16 i f flag :
17 return array
18 # For keeping the negative items
19 neg = {}
20 for i in range(len( array ) ) :
21 # if current item is negative
22 i f array [ i ] < 0:
23 ’’’
24 add index:value into
25 negatives dictionary
26 ’’’
27 neg[ i ] = array [ i ]
28 # Temporarily remove negative items
29 array = [ i for i in array i f i >= 0]
30 # Sorting using bubblesort algorithm
31 array=bubblesort ( array )
4.18 Numbers First, Characters Second 175
In this challenge, while the structure of the given nested list is kept, the nested list
must be sorted such that the numbers and then characters are to be sorted. Both
numbers and characters must be sorted in ascending order. Write a function that as
input, takes a nested list consisting of numbers and characters and returns a nested
list with the same size of lists such that the numbers and then characters are sorted.
For some inputs, the expected outputs are illustrated in Table 4.18.
Algorithm
The algorithm first flattens the nested list into a single list, then separates the numbers
and characters, sorts them using Bubble Sort, and finally merges them back into a
sorted list with the original structure of nested lists. The Python code to sort numbers
and then characters is depicted in Code 4.18.
Code 4.18 Python code to sort positives numbers and keep negatives
1 def number_then_character(NestedList ) :
2 # Sorting by bubble sort
3 def bubblesort ( l s t ) :
4 for i in range(len( l s t ) ) :
5 flag = True
Table 4.18 The expected outputs for certain inputs to sort numbers first and characters second
NestedList Expected output
[[0, 0, 0.5, 1], [3], [5, 5, ‘X’, ‘Y’], [‘Z’, ‘a’], [[0, 0, 0.5, 1], [3], [5, 5, ‘X’, ‘Y’], [‘Z’, ‘a’],
[‘b’, ‘er’, ‘f’], [‘p’, ‘s’]] [‘b’, ‘er’, ‘f’], [‘p’, ‘s’]]
[[2,74,3,0,0.5,],[4,7,‘a’,‘b’,‘e’,99]] [[0, 0.5, 2, 3, 4], [7, 74, 99, ‘a’, ‘b’, ‘e’]]
[[419,419,‘t’,‘r’,‘pol’],[‘x’,‘y’,88,‘r’]] [[88, 419, 419, ‘pol’, ‘r’], [‘r’, ‘t’, ‘x’, ‘y’]]
[[2,3,‘u’],[‘w’,100,4,5],[‘r’,‘d’,‘t’,1]] [[1, 2, 3], [4, 5, 100, ‘d’], [‘r’, ‘t’, ‘u’, ’‘w’]]
176 4 Number
Algorithm
It converts the given date times in format string to the date time object and sorts
them using the bubble sort algorithm, and after sorting, the date times objects are
converted to string object. The Python code to sort dates is depicted in Code 4.19.
Code 4.19 Python code to to sort dates
1 import datetime
2 def bubble_sort ( arr ) :
3 for i in range(len( arr ) − 1):
4 for j in range(0 , (len( arr ) − i ) − 1):
5 i f arr [ j ] > arr [ j + 1]:
6 # Swap if it is needed
7 arr [ j ] , arr [ j + 1] = arr [ j + 1] , arr [ j ]
8 return arr
9 def sort_dates (times , sort_types ) :
10 time_objects = []
11 sorted_dates=[]
12 # Iterate through items
13 wanted_date="%d−%m−%Y_%H:%M"
14 for t in times :
15
16 time_objects .append(
Table 4.19 The expected outputs for certain inputs to sort the dates
times,sort_types Expected output
[‘09-02-2001_10:03’, ‘10-02-2000_18:29’, [‘01-01-1999_00:55’, ‘10-02-2000_18:29’,
‘01-01-1999_00:55’],‘ASC’ ‘09-02-2001_10:03’]
[‘01-04-2004_10:03’, ‘10-02-2006_03:29’, [‘01-04-2004_10:03’, ‘10-02-2006_03:29’,
‘01-01-2022_00:55’],‘ASC’ ‘01-01-2022_00:55’]
[‘01-04-2004_10:03’, ‘10-02-2006_03:29’, [‘01-01-2022_00:55’, ‘10-02-2006_03:29’,
‘01-01-2022_00:55’],‘DSC’ ‘01-04-2004_10:03’]
[‘09-02-2001_10:03’, ‘10-02-2000_18:29’, [‘09-02-2001_10:03’, ‘10-02-2000_18:29’,
‘01-01-1999_00:55’],‘DSC’ ‘01-01-1999_00:55’]
178 4 Number
This challenge is aimed to sort the given string and returns the sorted string such that
at first sort them in alphabetical order and then sort them by length. Write a function
that as input, takes a string and returns the sorted string in terms of alphabetical
order and length, respectively. For some inputs, the expected outputs are illustrated
in Table 4.20.
Table 4.20 The expected outputs for certain inputs to sort by alphabetical order and length
Sentence Expected output
‘Year of the Tiger, is it fog’ ‘Tiger, Year fog the it of is’
‘Python is one of the most used languages’ ‘languages Python most used the one of is’
‘FIFA World Cup Qatar’ ‘Qatar World FIFA Cup’
‘for if while def range else set’ ‘range while else def set for if’
4.20 Sorting by Alphabetical Order and Length 179
Algorithm
The algorithm takes a sentence as input, splits it into words, sorts them in alphabetical
order using the bubble sort algorithm, and then sorts them again based on their lengths.
This is done by iterating over the sorted list of words and comparing each word’s
length with the lengths of the preceding words. If a word is longer than a preceding
word, they are swapped. Finally, the sorted words are concatenated into a single
string and returned.
The Python code to sort the given string by alphabetical order and length is
depicted in Code 4.20.
Code 4.20 Python code to sort the given string by alphabetical order and length
1 def bubble_sort ( arr ) :
2 for i in range(len( arr ) − 1):
3 for j in range(0 , (len( arr ) − i ) − 1):
4 i f arr [ j ] > arr [ j + 1]:
5 # Swap if it is needed
6 arr [ j ] , arr [ j + 1] = arr [ j + 1] , arr [ j ]
7 return arr
8 def sorted_by_alphabetical_and_length (sentence ) :
9 words = sentence . s p l i t ()
10 # Sorting in alphabetical order
11 words=bubble_sort (words)
12 for word in range(0 , len(words) ) :
13 for i in range(0 , word) :
14 # Swap if the condition was met
15 i f len(words[word]) > len(words[ i ] ) :
16 temp = words[ i ]
17 words[ i ] = words[word]
18 words[word] = temp
19
20 ’’’
21 Each sorted word is added to sorted_sentence
22 (convert the list to string)
23 ’’’
24 sorted_sentence = ""
25 for item in range(0 , len(words) ) :
26 sorted_sentence += words[item] + ’’’ ’’’
27 return sorted_sentence
180 4 Number
Algorithm
Table 4.21 The expected outputs for certain inputs to sort by digit count
Array Expected output
[81181972,9,123198776,23,456,1] [1, 23, 456, 9, 123198776, 81181972]
[1,2,3,11,9,77,66,87,111] [1, 11, 111, 2, 3, 66, 77, 87, 9]
[39,456,0,7,3,599] [0, 3, 456, 7, 39, 599]
[] []
4.21 Sorting by Digit Count 181
51 def max_(a , b) :
52 """
53 It takes two positive integers a and b,
54 and returns the one whose highest
55 digit occurs more times. In case of
56 a tie, returns the larger number.
57
58 """
59 a , b = str (a) , str (b)
60 for i in range(9 , −1, −1):
61 i f a . count( str ( i )) > b. count( str ( i ) ) :
62 return int (a)
63 e l i f a . count( str ( i )) < b. count( str ( i ) ) :
64 return int (b)
65 return max( int (a) , int (b))
Chapter 5
String
This chapter talks about 13 string-based problems. These challenges are explained
with some examples and then programmed in Python. The problems are listed as
follows:
The pancake scramble problem is aimed to reverse characters of the given text t in
the order 2, 3, . . . , n, where n is the length of t. For example, t = ‘ python’, the steps
to scramble it are: The first reversing from the second character is considered (y),
‘ python’ → ‘ypthon’, another from third character (t) ‘ypthon’ → ‘t pyhon’ →
‘hypton’ → ‘ot pyhn’, nth character ‘ot pyhn’ → ‘nhypto’. Write a function that as
input, takes a string and applies pancake scramble to it. For some inputs, the expected
outputs are illustrated in Table 5.1.
© The Author(s), under exclusive license to Springer Nature Switzerland AG 2024 183
H. Izadkhah and R. Behzadidoost, Challenging Programming in Python: A Problem
Solving Perspective, https://doi.org/10.1007/978-3-031-39999-2_5
184 5 String
Table 5.1 The expected outputs for certain inputs for pancake scramble
t Expected output
‘python’ ‘nhypto’
‘Deep Learning has revolutionized Pattern ‘.otnoe rta eiotlvrshgire eDepLann a
Recognition’ eouinzdPtenRcgiin’
‘Challenging Programming’ ‘gimroPginlaChlegn rgamn’
‘x = 2x + 1(9 * 56y)’ ‘)6 * (+2x = x195y’
Algorithm
It takes a string as input and returns a new string that is a scrambled version of
the original string. It iterates over each index of the string and reverse the substring
of the original string up to that index, and merge the reversed substring with the
rest of the original string (i.e., the substring after the index) to create a new string.
The algorithm repeats this process for each index of the string and returns the final
scrambled string. The Python code to apply the pancake scramble in the given text
is depicted in Code 5.1.
Code 5.1 Python code to apply the pancake scramble in the given text
1 # a function that reverses a string using a for loop
2 def reverse_string ( s ) :
3 reversed_s = ' '
4 # Iterate over indices of s backwards
5 for i in range(len( s)−1, −1, −1):
6 '''
7 Append character at the
8 current index to reversed_s
9 '''
10 reversed_s += s [ i ]
11 # Return fully reversed string
12 return reversed_s
13
14 # Define the pancake_scramble function
15 def pancake_scramble_into_texts( t ) :
16 for i in range(len( t ) ) :
17 # Reverse substring up to index i
18 Reversed_String = reverse_string ( t [ : i +1])
19 # Slice the rest of the string
20 Orginal_String = t [ i +1:]
21 # Merge the reversed and original substrings
22 t = Reversed_String + Orginal_String
23 # Return the fully scrambled string
24 return t
5.2 Reverse Vowels into Texts 185
Table 5.2 The expected outputs for certain inputs for reversing vowels
t Expected output
‘Other’ ‘Ethor’
‘Deep Learning has revolutionized Pattern ‘Doip Liorneng hes ravelitoinuzod Pettarn
Recognition’ Ricagneteen’
‘Challenging Programming’ ‘Chillangong Prigremmang’
‘x = 2x + 1(9 * 56y)’ ‘)6 * (+2x = x195y’
In this challenge, a text is provided and a new text is generated in which the vowels
are reversed. Additionally, if a character at a specific index in the original text is
uppercase, the corresponding character in the new string will also be uppercase. For
example, if s = Other is the given text, o = Ethor is the new string generated that
its vowels are reversed. In this problem, the considered vowels are ‘aeiouAEIOU’.
For some inputs, the expected outputs are illustrated in Table 5.2.
Algorithm
For reversing vowels in a string, the algorithm performs iteration over the characters
of the input string, with additional iterations over the indices of the relevant vowel
characters. Specifically, the algorithm first extracts all the vowel characters and their
indices from the input string using a list comprehension that filters the characters by
membership in a set of vowels. Then, it iterates over the indices in reverse order and
collects the reversed vowels into a list. Finally, the program iterates over the original
vowel positions within the input string and replaces them with their corresponding
reversed vowels, while preserving the uppercase format of each vowel character
within its respective position. The Python code for reversing the vowels of the given
text is depicted in Code 5.2.
Code 5.2 Python code for reversing the vowels of the given text
1 def reverse_vowels_into_texts ( s ) :
2 # Set of vowels
3 vowels = set ("aeiouAEIOU")
4 chars = l i s t ( s )
5 vowel_indices = \
6 [ i for i in range(len( chars )) i f chars [ i ] in vowels]
7
8 # extract all the vowels and their indices
9 reversed_vowels = []
10 for i in range(len(vowel_indices)−1, −1, −1):
11 reversed_vowels .append( chars [vowel_indices[ i ] ] )
12
186 5 String
Table 5.3 The expected outputs for certain inputs for word shape
Words, shape Expected output
[‘congeed’, ‘outfeed’, ‘strolld’, ‘mail’, [‘congeed’, ‘outfeed’, ‘strolld’]
‘stopped’], [1, −1, −1, −1, 0, −1]
[‘eeten’, ‘good’, ‘aare’, ‘oozes’, ‘sstor’], [‘eeten’, ‘oozes’, ‘sstor’]
[0, 1, −1, 1]
13 '''
14 Replace the original vowel
15 positions with the reversed vowels
16 '''
17 j=0
18 for i in vowel_indices :
19 i f chars [ i ] . isupper ( ) :
20 chars [ i ] = reversed_vowels[ j ] . upper()
21 else :
22 chars [ i ] = reversed_vowels[ j ] . lower()
23 j+=1
24
25 return ' ' . join ( chars )
The shape of a given word w in length m is a list l that consisted of m − 1 of +1, −1,
and 0. The way that an integer is to be appended in l, depends on the alphabetical
order. The order is ‘a’ < ‘b’ < ‘c’ < ‘d’ < ‘e’ < ‘ f ’ < ‘g’ < ‘h’ < ‘i’ < ‘ j’ < ‘k’ <
‘l’ < ‘m’ < ‘n’ < ‘o’ < ‘ p’ < ‘q’ < ‘s’ < ‘t’ < ‘u’ < ‘v’ < ‘w’ < ‘x’ < ‘y’ < ‘z’.
For each alphabetical pair α and β, if α < β shape = 1, if α > β shape = −1, and if
α = β, shape = 0. For example, if the given wor d = optimum, what is the shape?
The steps to reach the shape are: o < p, so shape = [1] → p < t, so shape = [1, 1]
→ t > i, so shape = [1, 1, −1] → i < m, so shape = [1, 1, −1, 1] → m < u, so
shape = [1, 1, −1, 1, 1] → u > m, so shape = [1, 1, −1, 1, 1, −1]. In this chal-
lenge, all words whose shapes are equal to the given shape must be found. Write a
function that as input, takes a list of words (text Corpus) and shape, and return the
list of words whose shape is exactly the same as the given shape. For some inputs,
the expected outputs are illustrated in Table 5.3.
Algorithm
The algorithm applies a set of rules to determine the shape of a word, based on the
alphabetical order of its characters, and uses this shape to filter a list of words. The
rules are implemented using if-else statements. The Python code for computing and
returning all equal shapes with the given shape is depicted in Code 5.3.
5.4 Word Height from a Text Corpus 187
Code 5.3 Python code for computing and returning the all equal shapes with the given shape
1 def Word_Shape_from_a_Text_Corpus(words, shape ) :
2 output = []
3 # To iterate through the list of words
4 for i in words:
5 '''
6 Just consider the words that
7 equals with given shape
8 '''
9 i f len( i ) == len(shape)+1:
10 i f word_shape( i ) == shape :
11 output .append( i )
12 return output
13 def word_shape(word) :
14 # To create an array
15 shape = ([None] * (len(word) − 1))
16 for i in range(( len(shape ) ) ) :
17 '''
18 Ord as inpute takes a character and
19 returns an integer (unicode) such that
20 the alphabetical order is considered.
21 '''
22 '''
23 Determine the shape for a given word
24 using the ruled based criteria
25 '''
26 a = ord(word[ i ])
27 b = ord(word[ i +1])
28 i f (a<b) :
29 shape[ i ] = 1
30 e l i f (a==b) :
31 shape[ i ] = 0
32 e l i f (a>b) :
33 shape[ i ] = −1
34 return shape
The length of a word refers to the number of characters it contains, while the height
of a word indicates the number of meaningful sub-words that can be derived from
it. A word with no inherent meaning has a height of zero, whereas a word that is
meaningful and cannot be split into two meaningful sub-words has a height of one.
188 5 String
For words that can be broken down into sub-words, the height of the word is equal
to the highest height of its sub-words plus one. For example, the word ‘roqm’ has
no inherent meaning and, therefore, a height of zero. On the other hand, the word
‘chukker’ cannot be split into two meaningful sub-words, so its height is one. Finally,
for a word like ‘enterprise’ we can recursively break it down into sub-words until we
reach meaningless words, and its height is determined by the maximum height of its
sub-words. Write a function that as input, takes a list of words, denoted by wor ds
and a single word, denoted by wor d and returns the height of the word, where wor d
for finding its sub-words searches into wor ds. For some inputs, the expected outputs
are illustrated in Table 5.4.
It is important to note that the height of a word is determined based on the words
in the text corpus.
Algorithm
This algorithm recursively computes the height of a word by splitting it into smaller
parts, computing the heights of those parts recursively, and combining the heights
of the parts to obtain the height of the original word. Memoization is used to avoid
redundant computations and improve performance. The algorithm steps are outlined
in detail as follows:
1. It takes three inputs: ‘words’, a list of words in the text corpus, ‘word’, the word
whose height needs to be computed, and ‘memo’, an optional dictionary used to
memorize previously computed heights.
2. If ‘memo’ is not provided, an empty dictionary is created for memoization.
3. If the height of the current word has already been computed and stored in the
‘memo’, the memoized value is returned.
4. A binary search algorithm is utilized to search for a given word in the list of words.
If the word is found, the index of the word in the list is returned; otherwise, −1
is returned.
5. If the word is not present in the list of words, its height is 0, and 0 is returned,
and the algorithm is terminated.
6. A list, ‘validList’, is created to store all possible ways to split the word into two
parts and check if both parts are present in the list of words.
7. A loop iterates over all possible split positions in the word, from position 1 to
the length of the word −1. For each split position, the left and right parts of the
word are extracted.
8. If both the left and right parts are found in the list of ‘words’, they are added to
the ‘validList’.
9. If no valid splits are found, the height of the word is 1, and 1 is returned. 1
5.4 Word Height from a Text Corpus 189
10. A list, ‘hs’, is created to store the heights of all valid splits.
11. For each valid split (ls, rs), the height of the left and right parts is computed
recursively. If the height of a part has already been computed and stored in
the ‘memo’, the memoized value is used; otherwise, it is called recursively to
compute the height. The heights of both parts are added together, and 1 (the
original word is meaningful) is added to obtain the height of the current split.
12. The maximum height of all valid splits is stored in the ‘memo’ for the current
word, and it is returned.
The Python code to compute the height of a word is depicted in Code 5.4.
Code 5.4 Python code to compute the word height
1 '''
2 This function implements binary search
3 to search for a value in a sorted list
4 '''
5 '''
6 Binary search is a popular algorithm used for
7 searching an ordered list of elements.
8 '''
9 '''
10 It works by repeatedly dividing the search interval
11 in half until the target value is found or
12 the search interval becomes empty.
13 '''
14 def binary_search( lst , x) :
15 left = 0
16 right = len( l s t ) − 1
17
18 while l e f t <= right :
19 mid = ( l e f t + right ) / / 2
20 i f l s t [mid] < x:
21 l e f t = mid + 1
22 else :
23 right = mid − 1
24
25 return l e f t
26
27 '''
28 This function computes the height
29 of a given word in a list of words
30 by recursively computing the height
31 of its subwords
32 '''
33 def Word_Height_From_a_Text_Corpus(words, word, memo=None) :
34
190 5 String
80 return 1
81
82 hs = []
83 '''
84 Compute the height of each valid split
85 recursively and take the maximum
86 '''
87 for ( ls , rs ) in validList :
88 l e f t = memo. get ( ls , None) or \
89 Word_Height_From_a_Text_Corpus(words, ls , memo)
90 right = memo. get ( rs , None) or \
91 Word_Height_From_a_Text_Corpus(words, rs , memo)
92 hs .append(max( left , right ) + 1)
93
94 '''
95 Store the computed height of the current word
96 in the memo before returning it
97 '''
98 memo[word] = max(hs)
99 return max(hs)
In this challenge, three colors yellow, r ed, and blue are given, whose rules are as
follows: (1) if two similar colors are added, the output is equal to the similar color
(2) if two different colors are added, the output is the third color. For example, if the
given string is s = ‘r ybyr ’, so determines the output. From the most left index, pair
0 and 0 + 1 are considered, r and y leads to reach b and b is inserted in array A, the
next pair is 1 and 1 + 1, y and b leads to reach r , and r is inserted in array A, the next
pair is 2 and 2 + 1, b and y leads to reach r , and r is inserted in array A, the next
pair is 3 and 3 + 1, y and r leads to reach b, and b is inserted in array A, A = brr b.
From the most left index, pair 0 and 0 + 1 are considered, b and r leads to reach y
and y is inserted in array B, the next pair is 1 and 1 + 1, r and r leads to reach r and
r is inserted in array B, the next pair is 2 and 2 + 1, r and b leads to reach y, and
y is inserted in array B; B = yr y. From the most left index, pair 0 and 0 + 1 are
considered, y and r leads to reach b and b is inserted in array C, the next pair is 1
and 1 + 1, y and r leads to reach b, b is inserted in array C, C = bb. From the most
left index, pair 0 and 0 + 1 are considered, b and b leads to reach b and b is inserted
in the array D. The length D is one and, the only value in D is to be returned, so b
is the answer. Write a function that as input, takes a string consisting of colors and
returns one color from the combinations of the colors. For some inputs, the expected
outputs are illustrated in Table 5.5.
192 5 String
Table 5.5 The expected outputs for certain inputs to combine adjacent colors
Colors Expected output
‘rybyr’ ‘b’
‘rrrryybby’ ‘y’
‘rby’ ‘b’
‘bbbryryrybrrbyr’ ‘y’
Algorithm
It takes a list of color s as input and returns a single color. It does this by repeatedly
combining adjacent pairs of colors, until only one color remains. Specifically, it
divides the input list of colors into smaller lists of colors, and then combines each
pair independently. That final color is then returned as the output of the function. To
avoid recomputing the same combinations over and over again, the function stores
the results of previous combinations in a dictionary so that it can use them again
if needed. The Python code to find the last color of combined adjacent colors is
depicted in Code 5.5.
Code 5.5 Python code to find the last color of combined colors
1 def combine(a ,b) :
2 # Make a dictionary to find the valuse that is to be returned.
3 ColorFinder = {"b":{"y" : "r" , "r" : "y"} ,
4 "y":{"b" : "r" , "r" : "b"} ,
5 "r":{"b" : "y" , "y" : "b"}}
6 '''If the colors are the same,
7 so return one of them. otherwise,
8 use the dictionary to find the proper clor.
9 '''
10 i f (a==b) :
11 return a
12 else :
13 return ColorFinder[a ][b]
14 '''
15 This function takes a list of colors as input,
16 combines adjacent colors according to a set of
17 rules, and returns a single color.
18 '''
19 def combine_adjacent_colors( colors ) :
20 '''
21 Create a dictionary to store results of
22 previous calls to combine().
23 The keys are tuples of color pairs,
24 and the values are the combined colors.
5.5 Color Combination 193
25 '''
26 cache = {}
27
28 '''
29 Keep looping until there is only one
30 color left in the list.
31 '''
32 while len( colors ) > 1:
33 '''
34 Create a new list to store the results
35 of combining adjacent colors.
36 '''
37 TemparrayColors = ([None] * (len( colors ) − 1))
38
39 '''
40 Loop over adjacent pairs of colors
41 in the input list.
42 '''
43 for i in range(len(TemparrayColors ) ) :
44 '''
45 Check if the result for the current
46 color pair is already in the cache.
47 '''
48 i f ( colors [ i ] , colors [ i +1]) in cache :
49 # If it is, use the cached result.
50 TemparrayColors[ i ] = \
51 cache [( colors [ i ] , colors [ i +1])]
52 else :
53 '''
54 If it is not, call the combine() function
55 to get the result, store it in the cache,
56 and use it.
57 '''
58 result = combine( colors [ i ] , colors [ i +1])
59 cache [( colors [ i ] , colors [ i +1])] = result
60 TemparrayColors[ i ] = result
61
62 '''
63 Replace the input list with the new
64 list of combined colors.
65 '''
66 colors = TemparrayColors
67 # Return the final color.
68 return colors [0]
194 5 String
Table 5.6 The expected outputs for certain inputs to rewrite the digits
X Expected output
‘2999’ ‘999’
‘329’ ‘929’
‘101’ None
‘322097845’ ‘209784522097845’
Algorithm
An algorithm is used to rewrite a given string according to certain rules. This algo-
rithm takes an input string X and, based on its first digit, selects a corresponding
rule to apply to the digits. This process is then repeated recursively until there are
no more digits left in the string or until an digit that is not covered by the rules is
encountered. The Python code to rewrite the given string is depicted in Code 5.6.
Code 5.6 Python code to rewrite the given string
1 # A function to remove the first digit
2 def remove_first_digit (X) :
3 return X[1:]
4
5 '''
6 A function to slice string and
7 insert '2' in the middle
8 '''
5.7 Champernowne Word 195
9 def slice_and_append_2(X) :
10 return mcculloch(X[1:]) + '2 ' + mcculloch(X[1:])
11
12 # A function to reverse the string
13 def reverse (X) :
14 return mcculloch(X[1:])[:: −1]
15
16 # A function to double the slices
17 def double(X) :
18 return mcculloch(X[1:]) + mcculloch(X[1:])
19
20 def mcculloch(X) :
21 '''
22 A dictionary that maps the first
23 digit to the corresponding function
24 '''
25 functions = {
26 '2 ' : remove_first_digit ,
27 '3 ' : slice_and_append_2 ,
28 '4 ' : reverse ,
29 '5 ' : double ,
30 }
31 # If the first digit of X is in the dictionary
32 i f X[0] in functions :
33 '''
34 Call the corresponding function with
35 the remaining digits of X as input
36 '''
37 return functions [X[0]](X)
The Champernowne word is a lengthy string that does not contain comma separators.
It is composed of a sequence of numbers that begins with one and increases by
one. The objective of this challenge is to return the corresponding number for a
given index. It is important to note that this problem cannot be solved using the
conventional method, such as list.index, due to time and space constraints. To
address this challenge, a function should be written that receives a positive integer
n as input, representing the desired index or position, and returns the corresponding
number. For instance, in the seventh digit of the sequence ‘1, 2, 3, 4, 5, 6, 7, 8, 9,
10, ...’, there is the digit 8. The expected outputs for some inputs are presented in
Table 5.7.
196 5 String
Table 5.7 The expected outputs for certain inputs for champernowne word
X Expected output
12**214 ‘9’
7 ‘8’
717897987691852588770047 ‘2’
3111111198765431001 ‘1’
Algorithm
9 p_n += w
10 d += 1
11 # Considering another sequence
12 w *= 10
13
14 p = (n − p_i) / / (d + 1)
15
16 '''
17 Convert it to string and obtain the
18 index of the digit we want
19 '''
20
21 num = str (p_n + p + 1)
22 return num[(n − p_i) % (d + 1)]
Let v = {aeiou} be the set of vowels, and X and Y be the first and second words,
respectively. X has one group of vowels if at least i ∈ v, i exist in x, but if i + 1, i + 2,
i + 3, i + 4 exist in x, there is one group of vowels, too. For example, pythonist
has two groups of vowels, while word kee p has one group of vowels. This challenge
is aimed at the two given strings generating a new one. The rules for generating the
new string are:
1. If there is one vowel group in X just the characters before the vowel are kept,
and it concated with Y such that the first consonants in Y before the first vowel
are removed. For example, if X = ‘go’ and Y = ‘meaning’ be the given string
strings, the output is ‘geaning’.
2. If there is more than one vowel group in X just the characters before the second
vowel are kept, and it concated with Y such that the first consonants in Y before
the first vowel are removed. For example, if X = ‘ python’ and Y = ‘visual’
be the given string strings, the output is ‘ pythisual’.
Write a function that as input, takes two strings X and Y , and returns a new string
by a combination of X and Y with considering the rules above. For some inputs, the
expected outputs are illustrated in Table 5.8.
Algorithm
It takes two input strings, f ir st_wor d and second_wor d, and combines them into
a single string. The combination is done by selecting appropriate segments of each
input string. The first step in the algorithm is to identify the consecutive vowels
in each input string. This is done by iterating over each character in the string and
198 5 String
Table 5.8 The expected outputs for certain inputs for combining the strings
First, second Expected output
‘go’, ‘meaning’ ‘geaning’
‘python’, ‘visual’ ‘pythisual’
‘elliot’, ‘bill’ ‘ill’
‘ross’, ‘jules’ ‘rules’
21 first_vowel_groups .append([ i ])
22
23 '''
24 Extract consecutive vowels
25 from the second word
26 '''
27 second_vowel_groups = []
28 for i in range(len(second_word ) ) :
29 i f second_word[ i ] in vowels:
30 '''
31 If the previous character is also
32 a vowel, add the index to the
33 previous sublist
34 '''
35 i f i > 0 and second_word[ i−1] in vowels:
36 second_vowel_groups[−1].append( i )
37 '''
38 Otherwise, create a new sublis
39 for the current vowel
40 '''
41 else :
42 second_vowel_groups .append([ i ])
43
44 # Determine the segment of the first word to keep
45 '''
46 If there are no consecutive vowels
47 in the first word, keep the whole word
48 '''
49 i f len( first_vowel_groups) == 0:
50 fw_segment = first_word
51 '''
52 If there is only one group of
53 consecutive vowels, keep everything
54 in the first word up to the first vowel
55 '''
56 e l i f len( first_vowel_groups) == 1:
57 fw_segment = first_word [ : first_vowel_groups [0][0]]
58 '''
59 Otherwise, keep everything in the
60 first word up to the second-to-last
61 group of consecutive vowels
62 '''
63 else :
64 fw_segment = first_word [ : first_vowel_groups[−2][0]]
65
200 5 String
66 '''
67 Determine the segment of the second
68 word to keep, which starts at the
69 first vowel of the second word
70 '''
71 sw_segment = second_word[second_vowel_groups[0][0]:]
72
73 return fw_segment + sw_segment
Algorithm
Suppose we are given a string ‘word’ and a list of words ‘words’. To unscramble
‘word’, we perform the following steps:
1. Create an empty array ‘res’ to store the similar words.
2. Iterate over each word ‘w’ in ‘words’ using a linear search.
3. For each word ‘w’, check if it has the same length as ‘word’ and if its first and
last letters are the same as those of ‘word’.
4. If the checks in previous steps are successful, check if the first and last letters
are the same as the letters of ‘word’.
5. If the checks in steps 3 and 4 are successful, add ‘w’ to the ‘res’ array.
6. Repeat steps 3–5 for all words in ‘words’.
7. Return the ‘res’ array containing the similar words.
Table 5.9 The expected outputs for certain inputs to unscramble a given word
Words, word Expected output
[‘pycorn’, ‘pipline’, ‘python’, ‘ceo’, ‘we’], [‘python’]
‘pohytn’
[‘camerier’, ‘academic’, ‘company’, [‘camerier’, ‘creamier’]
‘creamier’], ‘ceamierr’
5.10 Auto-Correcter Word 201
To auto-correct words, several methods can be used. One of the most widely used
techniques is keyword distance. This method involves replacing a word with the clos-
est letter to the intended word based on their proximity on a keyboard. For instance, if
the intended word is ‘car’, but the input word is ‘csr’, the letter ‘a’ which is adjacent
to ‘s’ on the keyboard should replace ‘s’, so ‘csr’ → ‘car’. This challenge requires
computing all keyword distances between the given word and other words in a list,
and then replacing the given word with the word that has the minimum keyword
distance. Write a function that as input, takes a string wor d, a list of words wor ds,
and for each w in wor d, returns w that its distance against wor d is minimum. For
some inputs, the expected outputs are illustrated in Table 5.10.
Algorithm
Suppose we are given a string ‘word’ and a list of words, denoted by ‘words’. For
each word ‘w’ in words, the algorithm checks if ‘w’ and ‘word’ have the same length.
202 5 String
Table 5.10 The expected outputs for certain inputs to auto-correct a given word
Words, word Expected output
[‘pycorn’, ‘pipline’, ‘python’, ‘ceo’, ‘we’], ‘python’
‘pohytn’
[‘camerier’, ‘academic’, ‘company’, ‘creamier’
‘creamier’], ‘ceamierr’
If they do, the algorithm computes the QW E RT Y keyboard distance between each
pair of characters in ‘w’ and ‘word’, stores the distances in an array storage, and
computes the sum of the distances. The sum is then assigned to ‘w’. This process is
repeated for all words in ‘words’. Finally, the algorithm returns the word from words
that has the minimum distance to given ‘word’. The Python code to auto-correct a
given word is depicted in Code 5.10.
Code 5.10 Python code to auto-correct a given word
1 def keyword_distance ( ) :
2 # The order of letters in each line of usual keywords
3 top = {c : (0 , i ) for ( i , c) in enumerate("qwertyuiop")}
4 mid = {c : (1 , i ) for ( i , c) in enumerate("asdfghjkl")}
5 bot = {c : (2 , i ) for ( i , c) in enumerate("zxcvbnm")}
6 # To update the dictionary with more than one argument
7 keys = dict (top , **mid, **bot)
8 dist = dict ()
9 lows = "abcdefghijklmnopqrstuvwxyz"
10 # Computing the distance
11 for cc1 in lows:
12 for cc2 in lows:
13 (r1 , c1) = keys[cc1]
14 (r2 , c2) = keys[cc2]
15 dist [(cc1 , cc2)] = \
16 (abs( r2 − r1 ) + abs(c2 − c1)) ** 2
17 return dist
18 dist=keyword_distance ()
19 # calls keyword_distance
20 '''
21 By using this function, there is no need
22 to compute the distance among all pairs each time.
23 '''
24 def ds(c1 , c2 ) :
25 return dist [(c1 , c2)]
26 def autocorrectr_word (words,word) :
27 '''
28 Extract words that has same
5.11 Correct Verb Form in Spanish 203
In this challenge, the task is to find the correct forms of the verb in the Spanish
language. Write a function that as input, takes verb, subject and tense, and returns
the correct forms of the verb in the Spanish language. For some inputs, the expected
outputs are illustrated in Table 5.11.
Algorithm
There are 3 types of regular verbs in Spanish. Hence; the three conditions are con-
sidered and for each of them, the three if condition specifies the type of their tense.
For considering the type of time and verb, a Python dictionary is made. The keys
Table 5.11 The expected outputs for certain inputs to find correct verb form in Spanish
Verb, subject, tense Expected output
‘ganar’, ‘ustedes’, ‘pretérito’ ‘ganaron’
‘escribir’, ‘ellos’, ‘imperfecto’ ‘escribían’
‘tomar’, ‘nosotros’, ‘futuro’ ‘tomaremos’
204 5 String
in the dictionary indicate the subjects, and values indicate the values that are to be
added to the given verb. In a simple statement, if the subject is found, add the value
to the given word. The Python code to find the correct form of a verb in the Spanish
language is depicted in Code 5.11.
Code 5.11 Python code to find the correct form of a verb into the Spanish language
1 def Correct_verb_form_in_Spanish(verb , subject , tense ) :
2 '''
3 A dictionary to store the letters
4 that will be added to the verb.
5 The key in di are subjects, and
6 valuse are objects that are to
7 be added to the verbs
8 '''
9 di = {}
10 # The first regular verbs
11 i f verb[−2::] == ' ar ' :
12 # if the tense is present
13 i f tense == ' presente ' :
14 di ={ 'yo ' : 'o ' , ' tú ' : ' as ' ,
15 ' él ' : ' a ' , ' ella ' :
16 ' a ' , ' usted ' : ' a ' ,
17 ' nosotros ' : 'amos ' ,
18 ' nosotras ' : 'amos ' ,
19 ' vosotros ' : ' áis ' ,
20 ' vosotras ' : ' áis ' ,
21 ' ellos ' : 'an ' ,
22 ' ellas ' : 'an ' ,
23 ' ustedes ' : 'an '
24 }
25
26 e l i f tense == ' pretérito ' :
27 di = { 'yo ' : ' é ' , ' tú ' : ' aste ' ,
28 ' él ' : 'ó ' , ' ella ' : 'ó ' ,
29 ' usted ' : 'ó ' ,
30 ' nosotros ' : 'amos ' ,
31 ' nosotras ' : 'amos ' ,
32 ' vosotros ' : ' asteis ' ,
33 ' vosotras ' : ' asteis ' ,
34 ' ellos ' : ' aron ' ,
35 ' ellas ' : ' aron ' ,
36 ' ustedes ' : ' aron '
37 }
38 e l i f tense == ' imperfecto ' :
39 di = { 'yo ' : 'aba ' , ' tú ' : ' abas ' ,
5.11 Correct Verb Form in Spanish 205
130 '''
131 i f tense == ' futuro ' :
132 di = { 'yo ' : ' é ' , ' tú ' : ' ás ' ,
133 ' él ' : ' á ' , ' ella ' : ' á ' ,
134 ' usted ' : ' á ' ,
135 ' nosotros ' : 'emos ' ,
136 ' nosotras ' : 'emos ' ,
137 ' vosotros ' : ' éis ' ,
138 ' vosotras ' : ' éis ' ,
139 ' ellos ' : 'án ' , ' ellas ' : 'án ' ,
140 ' ustedes ' : 'án '
141 }
142 '''
143 If the tense is future, then the
144 last two letters of the verb are not removed.
145 '''
146 return verb + di [ subject ]
147 '''
148 If the tense is not future, then the
149 last two letters of the verb are removed.
150 '''
151 return verb [ : len(verb) − 2:] + di [ subject ]
A substring is a string whose order is the same as the original string, while a sub-
sequent is a string in which the order of the letters is not necessarily the same as
the original string. For example, ‘tho’ is a substring of python, while theano is a
subsequent of python. Write a function that as input, takes letter as a list of letters,
and wor ds as a list of words, and returns all words that have the subsequent letter .
For some inputs, the expected outputs are illustrated in Table 5.12.
Table 5.12 The expected outputs for certain inputs for finding the words that have the same
subsequent letters
Words, letter Expected output
[‘suits’, ‘refluxed’, ‘trip’, ‘refluxing’, [‘refluxed’, ‘refluxing’, ‘retroflux’]
‘retroflux’], reflux
[‘vasomotor’, ‘bathythermogram’, [‘bathythermogram’, ‘benzhydroxamic’]
‘benzhydroxamic’, ‘dialer’], byoam
208 5 String
Algorithm
It is used a combination of nested loops and string manipulation to find the words
that have the same subsequent letters. The algorithm loops over each word in the
input list and checks if the word is at least as long as the letters we’re looking for. If
so, the word is converted to a list of characters, and another loop is used to check if
each letter we’re looking for is present in the word. If all the letters are found in the
word, the word is added to a list of matching words. Finally, the algorithm returns the
list of matching words. The Python code to find all words that have the subsequent
letters is depicted in Code 5.12.
Code 5.12 Python code to find all words that have the subsequent letters
1 def subsequent_letters (words, l e t t e r s ) :
2 '''Get the length of the letters
3 we are looking for
4 '''
5 len_let = len( l e t t e r s )
6 '''
7 Initialize an empty list
8 to store the matching words
9 '''
10 ST = []
11
12 # Loop over each word in the input list
13 for term in words:
14 '''
15 Check if the word is at least as long as
16 the letters we're looking for
17 '''
18 i f len(term) >= len( l e t t e r s ) :
19 # Convert the word to a list of characters
20 indterm = l i s t (term)
21 '''
22 Initialize a counter and index for
23 tracking the letters we've found
24 '''
25 counter = 0
26 CurrentIndex = −1
27
28 '''
29 loop over each letter we're looking for
30 '''
31 for l e t in l e t t e r s :
32 '''
33 Check if the letter is in the remaining
5.13 Possible Words from a Text Corpus 209
In this challenge, for a given string pattern, all words that include the pattern must be
found. For example, if p = ∗ ∗ ∗b ∗ ls is the given pattern, ‘ jumbals’ and ‘ver bals’
are words that include the letters of the pattern. Write a function that as input, takes
a string pattern, and returns all words that include the pattern. For some inputs, the
expected outputs are illustrated in Table 5.13.
Table 5.13 The expected outputs for certain inputs for extracting possible words from a text corpus
Words, pattern Expected output
[‘pepsi’, ‘fissury’, ‘dark’, ‘missary’, ‘missort’] [‘fissury’, ‘missary’, ‘missort’]
, ‘*iss*r*’
[‘havened’, ‘car’, ‘hoveled’, ‘people’, [‘havened’, ‘hoveled’, ‘hovered’]
‘hovered’] ‘h*ve*ed’ ,
210 5 String
Algorithm
Let wor ds be a list of words given, and patter n be a string that includes the letters.
For each wor d in wor ds, it encodes all letters of wor d and patter n. It checks if all
letters in patter n are in wor d, and their encoding is the same, store wor d into the
array r esult, where r esult is all words that include patter n.
The Python code to find all words that have the given string pattern is depicted in
Code 5.13.
Code 5.13 Python code to find all words that have the given string pattern
1 def encode(word, pattern ) :
2 '''
3 In python, encoding of * is 42
4 '''
5 encoding_pattern = l i s t ( pattern . encode( ) )
6 encoding_word = l i s t (word. encode ( ) )
7 pattern_filter = \
8 [x for x in encoding_pattern i f x != 42]
9 encoded_word = []
10 '''
11 It is enough if the letters in word be in pattern.
12 It doesn't matter what the rest of the letters are.
13 '''
14 for int_ in encoding_word:
15 i f int_ in pattern_filter :
16 encoded_word.append( int_ )
17 else :
18 encoded_word.append(42)
19 return encoding_pattern , encoded_word
20
21 def possible_words(words, pattern ) :
22 '''
23 Encode the pattern and each word, and
24 if their encoding is equal, consider
25 the word as a possible one.
26 '''
27 result = []
28 pattern_encoding = encode( ' ' , pattern )[0]
29 for word in words:
30 '''
31 To avoid checking all words,
32 if any two words have the same length, then
33 they are encoded.
34 '''
35 i f len(word) == len( pattern ) :
5.13 Possible Words from a Text Corpus 211
This chapter discusses 14 game-based problems, which are explained through exam-
ples and subsequently programmed in Python. The problems are as follows:
1. Determining the card that leads the player to win the game
2. Hand shape in Bridge game
3. Obtaining the abbreviations in the contract bridge game
4. Same hand shape distribution in a card game
5. The number of rounds in a given permutation
6. Reaching stable state in candy share
7. African Oware game
8. The number of Safe Squares Rooks of Chessboard
9. The number of Safe Squares not threatened by bishops
10. Reaching Knight jump
11. Capturing maximum checkers in chessboard
12. The number of safe squares for friend pieces in a chessboard
13. Crag Score
14. Optimal crag score with multiple rolls.
In playing card games, there is a game with four players each one has one card
in form (rank, suit), where a suit is a category of the cards. If a trump card is
included in the game, so trump is one of the elements in c, c = {‘clubs , ‘spades ,
‘hear ts , ‘diamonds }. The order of ranks is ‘ace > ‘king > ‘queen > ‘ jack >
10 > 9 > 8 > 7 > 6 > 5 > 4 > 3 > 2 > 1. With some tricks, one can win the
game. The rules for the tricking are as the followings:
1. If a trump card is given, the first trump card with the highest rank is selected,
and its player wins the game.
© The Author(s), under exclusive license to Springer Nature Switzerland AG 2024 213
H. Izadkhah and R. Behzadidoost, Challenging Programming in Python: A Problem
Solving Perspective, https://doi.org/10.1007/978-3-031-39999-2_6
214 6 Game
Table 6.1 The expected outputs for certain inputs for determining the winner in the card game
Cards, trump Expected output
[(‘three’, ‘clubs’), (‘king’, ‘spades’), (‘queen’, (‘queen’, ‘clubs’)
‘clubs’), (‘jack’, ‘hearts’)] , queen
[(‘four’, ‘diamonds’), (‘ace’, ‘clubs’), (‘four’, (‘four’, ‘diamonds’)
‘spades’), (‘king’, ‘clubs’)],None
[(‘eight’, ‘hearts’), (‘three’, ‘diamonds’), (‘queen’,‘hearts’)
(‘nine’, ‘spades’), (‘queen’, ‘hearts’)] , None
2. If a trump card is not given, the first card with the highest rank is selected, and
its player wins the game.
For example, if cards=[(‘three’, ‘clubs’), (‘king’, ‘spades’), (‘queen’, ‘clubs’),
(‘jack’, ‘hearts’)], and tr ump = queen, the first player with the card (‘queen ,
‘clubs ) is won. Although (‘thr ee , ‘clubs ) is the first card, but (‘queen , ‘clubs )
has more rank. In another example, if cards=[(‘four’, ‘diamonds’), (‘ace’, ‘clubs’),
(‘four’, ‘spades’), (‘king’, ‘clubs’)], and tr ump = N one, the first player with the
card (‘ f our , ‘diamonds ) is won. For some inputs, the expected outputs are illus-
trated in Table 6.1.
Write a function that as input, takes a list of cards, and returns, the card that leads
the player to win the game.
Algorithm
For each suit of spades, hearts, diamonds, and clubs, the program stores their respec-
tive ranks and sorts them using the bubble sort algorithm according to a set of rules.
In the subsequent step, the program selects the card with the highest rank based on
the following criteria: If a trump card is given as input, it selects the first trump card
with the highest rank. If a trump card is not given in the input, it selects the first
card with the highest rank. The Python code to find and return the card that leads the
player to win the game is depicted in Code 6.1.
Code 6.1 Python code to find and return the card that lead the player to win the game
1 def bubble_sort ( arr ) :
2 for i in range(len( arr ) − 1):
3 for j in range(0 , (len( arr ) − i ) − 1):
4 i f arr [ j ] > arr [ j + 1]:
5 # Swap if it is needed
6 arr [ j ] , arr [ j + 1] = arr [ j + 1] , arr [ j ]
7 return arr
8 def Winner_in_Card_Game(cards , trump=None) :
9 names =[x[1] for x in cards ]
10 ’’’
6.1 Winner in Card Game 215
56
57 e l i f item[1] == ’ hearts ’ :
58 i f item[0] == ’ace ’ :
59 hearts .append(50)
60 e l i f item[0] == ’king ’ :
61 hearts .append(40)
62 e l i f item[0] == ’queen’ :
63 hearts .append(30)
64 e l i f item[0] == ’jack ’ :
65 hearts .append(20)
66 e l i f item[0] == ’one’ :
67 hearts .append(1)
68 e l i f item[0] == ’two’ :
69 hearts .append(2)
70 e l i f item[0] == ’ three ’ :
71 hearts .append(3)
72 e l i f item[0] == ’four ’ :
73 hearts .append(4)
74 e l i f item[0] == ’ five ’ :
75 hearts .append(5)
76 e l i f item[0] == ’ six ’ :
77 hearts .append(6)
78 e l i f item[0] == ’seven’ :
79 hearts .append(7)
80 e l i f item[0] == ’ eight ’ :
81 hearts .append(8)
82 e l i f item[0] == ’nine ’ :
83 hearts .append(9)
84 e l i f item[0] == ’ten ’ :
85 hearts .append(10)
86 e l i f item[1] == ’diamonds’ :
87 i f item[0] == ’ace ’ :
88 diamonds.append(50)
89 e l i f item[0] == ’king ’ :
90 diamonds.append(40)
91 e l i f item[0] == ’queen’ :
92 diamonds.append(30)
93 e l i f item[0] == ’jack ’ :
94 diamonds.append(20)
95 e l i f item[0] == ’one’ :
96 diamonds.append(1)
97 e l i f item[0] == ’two’ :
98 diamonds.append(2)
99 e l i f item[0] == ’ three ’ :
100 diamonds.append(3)
6.1 Winner in Card Game 217
In the card game bridge, each player has thirteen cards. In this challenge, the num-
ber of occurrences of each card must be returned, where the order of the cards is
{‘spades , ‘hear ts , ‘diamonds , ‘clubs }. Write a function that as input takes the
thirteen cards, and returns the number of the occurrences of each trump card in order
{‘spades , ‘hear ts , ‘diamonds , ‘clubs }. For one inputs, the expected output is
illustrated in Table 6.2.
6.3 Contract Bridge Game 219
Table 6.2 The expected outputs for certain inputs for hand shape in bridge game
Cards Expected output
[(‘jack’, ‘diamonds’), (‘jack’, ‘hearts’), [3, 2, 4, 4]
(‘seven’, ‘clubs’), (‘five’, ‘clubs’), (‘ace’,
‘diamonds’), (‘three’, ‘clubs’), (‘four’,
‘spades’), (‘three’, ‘spades’), (‘eight’,
‘spades’), (‘ace’, ‘hearts’), (‘five’, ‘diamonds’),
(‘two’, ‘clubs’), (‘queen’, ‘diamonds’)]
Algorithm
In the game of contract bridge, each player is dealt a hand of thirteen cards. The
ranks of these cards can be abbreviated to create a more visually appealing display.
The objective is to find the appropriate abbreviations for each rank, with the order
of cards always being spades, hearts, diamonds, and clubs. The abbreviations are as
follows: ‘A’ for Ace, ‘K’ for King, ‘Q’ for Queen, ‘J’ for Jack, and ‘x’ for all other
ranks. To accomplish this task, a function must be written that takes a list of thirteen
cards as input and returns the abbreviated form in the order ‘AQKJ’. The ‘x’ can be
placed in any position within the abbreviation order, and if a suit is empty, a ‘-’ is
to be placed in the corresponding position. For one inputs, the expected output is
illustrated in Table 6.3.
220 6 Game
Table 6.3 The expected outputs for certain inputs for hand shape in contract bridge game
Cards Expected output
[(‘three’, ‘clubs’), (‘ten’, ‘spades’), (‘jack’, ‘J x x A J x x x K x J x x
‘hearts’), (‘five’, ‘hearts’), (‘jack’, ‘clubs’),
(‘two’, ‘diamonds’), (‘eight’, ‘hearts’), (‘eight’,
‘clubs’), (‘three’, ‘spades’), (‘ace’, ‘hearts’),
(‘jack’, ‘spades’), (‘king’, ‘diamonds’), (‘six’,
‘hearts’)]
Algorithm
The algorithm first encodes the ranks of the cards in each suit as numeric values,
with ‘ace’ being assigned the lowest value (0) and ‘x’ being assigned the highest
value (4). Then, the algorithm uses the bubble sort algorithm to sort the cards in each
suit in ascending order based on their encoded rank. Finally, the algorithm replaces
the encoded values with the corresponding card names, such as ‘A’ for ‘ace’, ‘K’ for
‘king’, and so on, and returns the sorted cards for each suit as a string. The Python
code to find and return the abbreviations in the contract bridge game is depicted in
Code 6.3.
Code 6.3 Python code to find and return the abbreviations in contract bridge game is depicted in
1 def bubble_sort ( arr ) :
2 for i in range(len( arr ) − 1):
3 for j in range(0 , (len( arr ) − i ) − 1):
4 i f arr [ j ] > arr [ j + 1]:
5 # Swap if it is needed
6 arr [ j ] , arr [ j + 1] = arr [ j + 1] , arr [ j ]
7 return arr
8 def contract_bridge_game(hand) :
9
10 spades = []
11 hearts = []
12 diamonds = []
13 clubs = []
14 ’’’
15 It encodes the ranks for being
16 sortable in the next steps.
17 ’’’
18 for item in hand:
19 i f item[1] == ’spades ’ :
20 i f item[0] == ’ace ’ :
21 spades .append( ’0’ )
22 e l i f item[0] == ’king ’ :
23 spades .append( ’1’ )
6.3 Contract Bridge Game 221
24 e l i f item[0] == ’queen’ :
25 spades .append( ’2’ )
26 e l i f item[0] == ’jack ’ :
27 spades .append( ’3’ )
28 else :
29 spades .append( ’4’ )
30 e l i f item[1] == ’ hearts ’ :
31 i f item[0] == ’ace ’ :
32 hearts .append( ’0’ )
33 e l i f item[0] == ’king ’ :
34 hearts .append( ’1’ )
35 e l i f item[0] == ’queen’ :
36 hearts .append( ’2’ )
37 e l i f item[0] == ’jack ’ :
38 hearts .append( ’3’ )
39 else :
40 hearts .append( ’4’ )
41 e l i f item[1] == ’diamonds’ :
42 i f item[0] == ’ace ’ :
43 diamonds.append( ’0’ )
44 e l i f item[0] == ’king ’ :
45 diamonds.append( ’1’ )
46 e l i f item[0] == ’queen’ :
47 diamonds.append( ’2’ )
48 e l i f item[0] == ’jack ’ :
49 diamonds.append( ’3’ )
50 else :
51 diamonds.append( ’4’ )
52 e l i f item[1] == ’clubs ’ :
53 i f item[0] == ’ace ’ :
54 clubs .append( ’0’ )
55 e l i f item[0] == ’king ’ :
56 clubs .append( ’1’ )
57 e l i f item[0] == ’queen’ :
58 clubs .append( ’2’ )
59 e l i f item[0] == ’jack ’ :
60 clubs .append( ’3’ )
61 else :
62 clubs .append( ’4’ )
63 # specifying the absents
64 i f len(spades) == 0:
65 spades .append( ’−’ )
66 i f len( hearts ) == 0:
67 hearts .append( ’−’ )
68 i f len(diamonds) == 0:
222 6 Game
69 diamonds.append( ’−’ )
70 i f len( clubs ) == 0:
71 clubs .append( ’−’ )
72 bubble_sort (spades)
73 bubble_sort ( hearts )
74 bubble_sort (diamonds)
75 bubble_sort ( clubs )
76 # replacing the encodes with the wanted names
77 output = ’ ’ . join (spades)+’’’ ’’’+\
78 ’’’’’’. join ( hearts)+’’’ ’’’ +\
79 ’’’’’’. join (diamonds)+\
80 ’’’ ’’’+’’’’’’. join ( clubs )
81 output = output . replace ( ’0’ , ’A’ ) \
82 . replace ( ’1’ , ’K’ ) . replace (
83 ’2’ , ’Q’ ) . replace ( ’3’ , ’J ’ ) \
84 . replace ( ’4’ , ’x’ )
85 return output
In this challenge, the two hands that have different permutations can be considered
as the same. For example, [6, 3, 2, 2] and [2, 3, 6, 2] have the same shape. Write a
function that as input takes a list of hands, and returns a list of tuples that contain
the same shapes, where the tuples are sorted in descending order, and the list of
tuples is sorted in ascending order. For one input, the expected output is illustrated
in Table 6.4.
Algorithm
By using a linear search, the found suits are enumerated and inserted into an array,
and it applies the wanted sorts to the considered array. The Python code to find and
return the shapes that contain the same distributions is depicted in Code 6.4.
Code 6.4 Python code to find and return the shape that contains the same distributions
1 def insertion_sort_descending ( arr ) :
2 for i in range(1 , len( arr ) ) :
3 key = arr [ i ]
4 j = i−1
5 while j >= 0 and key > arr [ j ] :
6 arr [ j + 1] = arr [ j ]
7 j −= 1
8 arr [ j + 1] = key
6.4 Same Hand Shape Distribution 223
Table 6.4 The expected output for certain input for same hand shape distribution
Cards, trump Expected output
[(‘two’, ‘hearts’), (‘nine’, ‘spades’), (‘two’, [((4, 3, 3, 3), 1), ((5, 3, 3, 2), 1), ((5, 4, 2, 2), 1),
‘clubs’), (‘eight’, ‘diamonds’), (‘queen’, ((6,4,2,1), 1)]
‘diamonds’), (‘ace’, ‘clubs’), (‘six’,
‘diamonds’), (‘queen’, ‘hearts’), (‘three’,
‘hearts’), (‘queen’, ‘clubs’), (‘ten’, ‘spades’),
(‘nine’, ‘clubs’), (‘six’, ‘spades’)], [(‘five’,
‘diamonds’), (‘jack’, ‘hearts’), (‘three’,
‘spades’), (‘king’, ‘clubs’), (‘two’, ‘spades’),
(‘king’, ‘spades’), (‘jack’, ‘spades’), (‘jack’,
‘diamonds’), (‘seven’, ‘clubs’), (‘nine’,
‘hearts’), (‘two’, ‘hearts’), (‘king’, ‘hearts’),
(‘eight’, ‘hearts’)], [(‘queen’, ‘clubs’), (‘jack’,
‘clubs’), (‘two’, ‘diamonds’), (‘nine’,
‘spades’), (‘six’, ‘clubs’), (‘ace’, ‘clubs’),
(‘ten’, ‘diamonds’), (‘nine’, ‘diamonds’),
(‘three’, ‘clubs’), (‘five’, ‘hearts’), (‘eight’,
‘spades’), (‘six’, ‘spades’), (‘eight’, ‘hearts’)],
[(‘seven’, ‘spades’), (‘ten’, ‘spades’), (‘two’,
‘hearts’), (‘two’, ‘clubs’), (‘jack’, ‘spades’),
(‘five’, ‘spades’), (‘queen’, ‘clubs’), (‘king’,
‘hearts’), (‘king’, ‘clubs’), (‘seven’,
‘diamonds’), (‘eight’, ‘clubs’), (‘queen’,
‘spades’), (‘four’, ‘spades’)]]
9 return arr
10 def bubble_sort ( arr ) :
11 for i in range(len( arr ) − 1):
12 for j in range(0 , (len( arr ) − i ) − 1):
13 i f arr [ j ] > arr [ j + 1]:
14 # Swap if it is needed
15 arr [ j ] , arr [ j + 1] = arr [ j + 1] , arr [ j ]
16 return arr
17 def hand_shape_distribution (hands ) :
18 arr = []
19 arr1 = []
20 for i in range(len(hands ) ) :
21 hand_list = [0 , 0, 0, 0]
22 # Counting the number of occurrences
23 for j in hands[ i ] :
24 i f j [1] == ’spades ’ :
25 hand_list [0] += 1
26 e l i f j [1] == ’ hearts ’ :
27 hand_list [1] += 1
28 e l i f j [1] == ’diamonds’ :
224 6 Game
29 hand_list [2] += 1
30 e l i f j [1] == ’clubs ’ :
31 hand_list [3] += 1
32 hand_list= insertion_sort_descending ( hand_list )
33 arr .append( hand_list )
34 for i in arr :
35 arr1 .append([ i , arr . count( i ) ] )
36 # To remove the hands that have not the same shape
37 temp_list = []
38 for i in arr1 :
39 i f i not in temp_list :
40 temp_list .append( i )
41 arr1 = temp_list
42 #Converting to tuple
43 for j in range(len( arr1 ) ) :
44 arr1 [ j ][0] = tuple( arr1 [ j ][0])
45 arr1 [ j ] = tuple( arr1 [ j ])
46 # Sorting in ascending order
47 arr1=bubble_sort ( arr1 )
48 return arr1
In this challenge, you are given an array of numbers which may be either sorted or
unsorted. The array is filled with numbers from a permutation of 0 to n − 1. The
objective of this challenge is to compute the number of rounds required to collect
the numbers in ascending order. In the first round, the numbers are considered in
ascending order. In the subsequent rounds, the numbers that have not been considered
in the previous rounds are taken into account, again in ascending order. This process
is repeated until all the numbers in ascending order have been visited. For example,
let us consider the given list l = [0, 4, 3, 5, 2, 1]. In the first round, 0 and 1 are in
ascending order, in the second round, just 2 is in ascending order, in the third round, 3
is in ascending order, and in the fourth round, 4 and 5 are in ascending order. Hence,
there are four rounds for list L. Write a function that as input takes a permutation of
numbers from 0 to n − 1, and returns the numbers of rounds. For some inputs, the
expected outputs are illustrated in Table 6.5.
Algorithm
To solve this challenge the method of inverse permutation is used. Let per m be
the given array, and inver seper m is an array equal to size per m that is filled with
6.5 Number Round Counter 225
Table 6.5 The expected outputs for certain inputs for counting the rounds in an array
Perm Expected output
[0, 1, 5,4,2, 3] 3
[0, 1,2,4,3,5] 2
[4, 11, 2,8, 6, 9, 5, 3,0 ,10, 1, 12,7] 6
[0,1,4,3,2] 3
zeros initially, inver seper m is utilized to inverse the given permutation. For each i in
per m, statement inver seper m[ per m[i]] = i inverse the permutations. To count the
number of rounds r ounds is defined. Initially, r ounds is set to 1, as there is always
a sequence of numbers in ascending order that the sequence, where the cardinality
of the sequence is at least one. Let n be the cardinality of inver seper m, for k = 1
to n, if inver seper m[k] < inver seper m[k − 1], so k is on the left side k − 1, and
r ounds must be incremented by one. The Python code to compute and return the
number of rounds in which the numbers are collected in ascending order is depicted
in Code 6.5.
Code 6.5 Python code to compute the number of rounds to collect the numbers in ascending order
1 def Number_round_counter(perm) :
2 ’’’
3 perm is an array that consisted
4 of numbers from 0 to n-1
5 ’’’
6 # To store the number of rounds
7 rounds = 1
8 ’’’
9 Create an array with the
10 size the of perm array
11 ’’’
12 inverse_perm = [0] ∗ len(perm)
13 for i in range(len(perm) ) :
14 ’’’
15 Inversing the the perm array
16 ’’’
17 inverse_perm[perm[ i ]] = i
18 for k in range(1 , len(inverse_perm ) ) :
19 ’’’
20 In the inverse_perm array,
21 if each element is smaller than
22 its previous element,
23 it means that this number is on
24 the left side of its previous
25 number in the perm list, as a result,
226 6 Game
A group of children is seated around a circular table with candies placed in front
of them. The candies are indistinguishable from each other. In order to synchronize
the children, their teacher rings a bell. When the bell rings, each child who has at
least two candies must send one candy to the child on their left and one to the child
on their right. Children with one or zero candies are not required to take any action.
The application of the pigeonhole principle demonstrates that when there are more
candies than children, the program will never terminate. Write a function that takes
the initial distribution of candies as its input and returns the number of steps required
to reach a stable state. A stable state is one in which it is not possible to transfer any
more candies to the right or left. The expected outputs for certain inputs are shown
in Table 6.6.
Algorithm
It recursively applies a set of rules to the input ‘candies’ list until a stable state is
reached, where no child has more than one candy. At each iteration, the algorithm
identifies a child with more than two candies and transfers one candy to each of its
adjacent children. This process is repeated until all children have at most one candy,
at which point the algorithm terminates and returns the number of states it took to
reach the stable state. The algorithm steps are outlined in detail as follows:
1. It takes two parameters: ‘candies’: a list of integers representing the number of
candies each child has. ‘states’ (optional): an integer representing the number of
states that the program has reached a stable state (default is 0).
Table 6.6 The expected outputs for certain inputs for reaching stable state in candy share
Candies Expected output
[0, 0, 0, 3] 1
[2, 0, 0, 1] 2
[2,0,0,0,0,0,4,0, 1] 8
[0,4,0,0,0,3,0, 1,0,0] 4
6.6 Reaching Stable State in Candy Share 227
Oware is an African board game with many variations its popular one is Mancala.
In this game, there is a board with two rows, and in each row, some holes (house),
and players perform ‘sow’ and can ‘capture’ seeds, where the seeds are in holes. In
this challenge, there is a board with size 2n, where the first n represents the houses
of the first player, and the last n represents the houses of the opponent. The seeds
are sowed and then are to be picked up, and the house captured has either two seeds
or three seeds. For example, if the inputs are boar d= [0, 2, 1, 2], and house = 1,
output an array that shows the changes after picking up the seeds. The first phase is
for sowing, where the sowing is started from position house + 1 to a value located in
boar d[house], and the value in house position (index) of boar d becomes zero, so
boar d =[0, 0, 1, 2]. In the second position, one seed is sown, so boar d= [0, 0, 2, 2],
in the next step, one seed in the third position is sown so boar d= [0, 0, 2, 3]. The
second and third positions are captured, as they are either two or three. Therefore
the output is [0, 0, 0, 0]. Write a function that as input, takes a board, and returns
an array that shows the changes after picking up the seeds. For some inputs, the
expected outputs are illustrated in Table 6.7.
Algorithm
The algorithm uses a while loop and a for loop to iterate over the Oware board and
sow the seeds to the houses and capture opponent’s seeds if applicable.
1. It takes boar d: a list representing the current state of the Oware board and house:
an integer representing the index of the house from which the player wants to
start sowing seeds.
Table 6.7 The expected outputs for certain inputs for African oware game
Board,house Expected output
[2, 1, 2,0],1 [2, 1, 2,0]
[1,4,5,6],1 [2, 0, 7, 7]
[7,7,7,68,0,1,0],3 [18, 18, 18, 0, 12, 13, 11]
[2, 0, 7, 7],1 [2, 0, 8, 7]
6.7 Oware Game 229
2. Determine the last index of the board by subtracting 1 from the length of the
board list, denoted by last_index.
3. Store the number of seeds in the selected house in a variable called seeds_to_sow.
4. Set the current index (curr ent_index) to the selected house plus 1.
5. Set the number of seeds in the selected house to 0.
6. While seeds_to_sow is greater than 0, do the following:
a. If the current index goes beyond the last index, go back to the first index.
b. If the current index is equal to house, skip the starting house.
c. Add one seed to the current house.
d. Reduce the number of seeds to sow by one.
e. Move to the next house by adding 1 to the current index.
a. Iterate through the opponent’s houses starting from the last house that
received a seed and moving backwards towards the opponent’s store.
b. For each opponent’s house, do the following:
i. If the house has 2 or 3 seeds, capture them and set the number of seeds
in the house to 0.
ii. Stop capturing if the opponent’s house has more than 3 seeds.
7. Return the updated boar d list.
The Python code to returns an array that shows the changes after picking up the
seed in the African oware game is depicted in Code 6.7.
Code 6.7 Python code to returns an array that shows the changes after picking up the seed in
African oware game
1 def oware_game(board , house ) :
2 # Determine the last index of the board
3 last_index = len(board) − 1
4 # Store number of seeds in the selected house
5 seeds_to_sow = board[house]
6 # Set the current index to the selected house
7 current_index = house + 1
8 # Set number of seeds in the selected house to 0
9 board[house] = 0
10 # Distribute the seeds to the adjacent houses
11 while seeds_to_sow > 0:
12 ’’’
13 If the current index goes
14 beyond the last index,
15 go back to the first index
16 ’’’
17 i f current_index > last_index :
18 current_index = 0
19 # Skip the starting house
20 i f current_index == house:
21 current_index += 1
230 6 Game
The rook is a game piece in the game of chess, and each rook is represented by a
two-tuple (row, column), where the rows and columns are numbered from 0 to n −1.
The rooks have the ability to invade an entire row or column on the n × n chessboard.
The objective of this challenge is to identify the set of safe squares on the chessboard
where no two rooks can attack them. Write a function that as input, takes rooks as a
list of tuples, and the size of the chessboard, and returns the number of safe squares.
For some inputs, the expected outputs are illustrated in Table 6.8.
6.9 Safe Squares Not Threaten with Bishops 231
Table 6.8 The expected outputs for certain inputs for counting the safe squares in a chessboard
n,rooks Expected output
10,[(2,3),(4,4)] 64
91,[(1,1),(4,4), (3, 5), (0, 7)] 7569
20,[(1,0),(3,6), (11, 5), (1, 2)] 272
7,[(0,2),(3,9), (3, 4)] 20
Algorithm
Let r ooks be the given lists of rooks, and n be the size of the chessboard. For
each i in r ooks, it stores i[0] into an array U nsa f er ow, and stores i[1] into an
array U nsa f ecol. In the next step, it obtains the safed rows and the safed columns
by sa f edr ow = n − len(set (U nsa f er )), sa f ecol = n − len(set (U nsa f ecol)),
receptively. In the last step, the number of safed squares is obtained by sa f edr ow ∗
sa f ecol.
The Python code for returning the number of safe squares in a chessboard is
depicted in Code 6.8.
Code 6.8 Python code for returning the number of safe squares in a chessboard
1 def Safe_Squares_Rooks_of_Chessboard(n, rooks ) :
2 Unsafe_squares_in_rows = []
3 Unsafe_squares_in_columns = []
4 for i in rooks :
5 Unsafe_squares_in_rows .append( i [0])
6 Unsafe_squares_in_columns .append( i [1])
7 # to remove duplicated numbers, set is apllied
8 safed_rows = n − len( set (Unsafe_squares_in_rows))
9 # to remove duplicated numbers, set is apllied
10 safed_columns=n −len( set (Unsafe_squares_in_columns))
11 # Obtaining the safed_squares
12 safe = safed_rows ∗ safed_columns
13 return safe
There is a n × n chessboard with some bishops pieces on it, where the rows and
columns are numbered from zero to n − 1. The elephant pieces can only move
diagonally. The bishops can threaten the squares of the chessboard. Write a function
that as input takes bishops as a list of tuples, and the size of the chessboard and returns
232 6 Game
Table 6.9 The expected outputs for certain inputs for counting the safe squares that are not threat-
ened with bishops
n,bishops Expected output
10,[(2,3),(4,4)] 68
91,[(1,1),(4,4), (3, 5), (0, 7)] 8002
20,[(1,0),(3,6), (11, 5), (1, 2)] 307
7,[(0,2),(3,9), (3, 4)] 29
the number of squares that are not threatened by any bishops. For some inputs, the
expected outputs are illustrated in Table 6.9.
Algorithm
The algorithm takes as input the size of a chessboard ‘n’ and a list of bishops on the
board ‘bishops’. It calculates the number of safe squares on the board, that is, the
number of squares that are not occupied by a bishop or threatened by a bishop on the
same diagonal. The algorithm first initializes a variable ‘safe_squares’ to 0, which
will be used to count the number of safe squares. It then creates two sets ‘diagonal1’
and ‘diagonal2’ to store the occupied squares on each diagonal of the chessboard.
For each bishop on the board, the algorithm calculates the indices of the squares on
the two diagonals that are threatened by the bishop, and adds them to the respective
sets ‘diagonal1’ and ‘diagonal2’. Finally, the algorithm iterates over all squares on
the board and checks if each square is occupied or threatened by a bishop on the
same diagonal. If a square is not occupied or threatened, the algorithm increments
the count of safe squares by 1. The algorithm returns the count of safe squares as the
output. The Python code for returning the number of safe squares in a chessboard
with bishops is depicted in Code 6.8.
Code 6.9 Python code for returning the number of safe squares in a chessboard with bishops
1 def Safe_Squares_not_Threaten_with_Bishops (n, bishops ) :
2 safe_squares = 0
3
4 # Store sets of occupied squares on each diagonal
5 # stores occupied squares on diagonal 1
6 diagonal1 = set ()
7 # stores occupied squares on diagonal 2
8 diagonal2 = set ()
9
10 # Iterate over bishops and update diagonal sets
11 for bishop in bishops :
12 # add square to diagonal 1
13 diagonal1 .add(bishop[0] + bishop[1])
6.10 Reaching Knight Jump 233
Table 6.10 The expected outputs for certain inputs to reach knight jump
Knight, start, end Expected output
(2,1,7),(3,5,9),(8,11,13) False
(3,4,2),(3,5,9),(1,7,9) False
(2, 1), (12, 10),(11, 12) True
(10, 5, 1), (20, 11, 16), (10, 12, 11) True
The cheeseboard game is typically played in two dimensions, but it can be extended
to k dimensions. In this game, a knight is represented by the head and neck of a horse.
In a two-dimensional chessboard, a knight can move to any of its eight neighboring
squares, while in a k-dimensional chessboard, it can move to squares in other dimen-
sions as well. The objective of this challenge is to determine whether a knight can
reach a given position on the chessboard, given its starting and ending coordinates.
The coordinates are represented by tuples of negative or non-negative integers. For
example, given a knight’s initial position of (2, 1, 7) and starting and ending coordi-
nates of (3, 5, 9) and (8, 11, 13), respectively, the challenge is to determine whether
the knight can reach its destination or not.
It is subtracted each value in the start tuple from each value in the stop tuple and
takes an absolute value from each result. The subtraction of |3 − 8|, |5 − 11| and
|9 − 13| are (5, 6, 4), respectively. The given position of the knight must be exactly
equal to the result of subtraction. Hence, as (2, 1, 7) is not equal to (5, 6, 4), (2, 1, 7)
is not reachable from the given start and stop positions. It is should be noted that
if c is the subtraction result, c must be sorted in descending order. Write a function
that as input, takes knight, start and stop coordinates, and returns True if the knight
is reachable from start and stop coordinates, else returns False. For some inputs, the
expected outputs are illustrated in Table 6.10.
234 6 Game
Algorithm
1. It takes in three arguments: knight, star t, and end. It returns True if a knight
can move from the start position to the end position on a chessboard, and False
otherwise.
2. It initializes an empty list called list_number s.
3. It loops through each element of the start position and computes the absolute
difference between the corresponding element in the start and end position.
4. It then appends this difference to the list_number s.
5. It sorts the list_number s in descending order using the bubble_sor t.
6. It loops through each element of the knight list. If any element of knight is not
in list_number s, it means that the knight cannot reach the target position. In
this case, the function returns False.
7. If all the elements of knight are present in list_number s, it means that the knight
can reach the target position. In this case, the function returns True.
The Python code for determining whether knight chess is reachable from the given
coordinates of the start and stop is depicted in Code 6.10.
Code 6.10 Python code for determining whether a knight chess is reachable from the given coor-
dinates of start and stop
1 ’’’
2 perform bubble sort on an input array
3 and return a reversed sorted array
4 ’’’
5 def bubble_sort ( arr ) :
6 n = len( arr )
7 for i in range(n − 1):
8 for j in range(0 , n − i − 1):
9 i f arr [ j ] < arr [ j + 1]:
10 ’’’
11 Swap the two elements if
12 they are in the wrong order
13 ’’’
14 arr [ j ] , arr [ j + 1] = arr [ j + 1] , arr [ j ]
15 return arr
16 ’’’
17 To determine whether a knight can reach
18 a given position on a k-dimensional chessboard
19 ’’’
20 def reaching_knight_jump(knight , start , end) :
21 ’’’
22 # Initialize an empty list to hold the
23 differences between start and end positions
24 ’’’
25 list_numbers = []
6.11 Capturing Maximum Checkers 235
26 for i in range(len( s t a r t ) ) :
27 ’’’
28 # Compute the absolute difference
29 between each element of start and end
30 and append to list_numbers
31 ’’’
32 list_numbers .append(abs( s t a r t [ i ] − end[ i ] ) )
33 # Sort the list of differences in descending order
34 list_numbers = bubble_sort ( list_numbers )
35 for num in knight :
36 ’’’
37 If any element of ‘knight‘ is not
38 in ‘list_numbers’,
39 the knight cannot reach
40 the target position
41 ’’’
42 i f num not in list_numbers :
43 return False
44 ’’’
45 Otherwise, return ‘True‘, indicating that
46 the knight can reach the target position
47 ’’’
48 return True
Table 6.11 The expected outputs for certain inputs for counting the maximum checkers
n, x, y, pieces Expected output
5,1,3, set([(2,4), (2,3),(2,2),(1,2),(3,3),(1,3)]) 1
8,0,4,set([(2,1), (3,1), (1,3),(4,1), (1,4)]) 2
10,4,7,set([(2,1), (9,1),(2,1), (6,5)]) 0
opponent, and returns the number of the most captured pieces in one move. For some
inputs, the expected outputs are illustrated in Table 6.11.
Algorithm
The algorithm takes as input the size of the chessboard ‘n’, the starting coordinates of
the king ‘x’ and ‘y’, the positions of the opponent’s pieces ‘pieces’, and the number
of pieces already removed ‘removed’. A BFS-based algorithm is used to explore all
possible moves from the current state of the board. It initializes a set called ‘visited’
to keep track of the states already visited during the breadth-first search and a queue
containing the starting state. It also initializes the current maximum to the number of
checkers already removed. The algorithm then enters a while loop and dequeues the
next state from the queue. It updates the current maximum to the maximum of the
current maximum and the number of checkers removed so far in this state. For each
possible diagonal jump direction, the algorithm computes the new position after the
jump and the position of the jumped-over checker. If the new position is outside the
board or there is already a checker at the new position or there is no checker at the
jumped-over position, the algorithm skips this direction. If the algorithm finds a new
state with a removed checker, it creates a new set of pieces without the jumped-over
checker and checks if this state has already been visited. If not, the algorithm adds the
new state to the visited set and the queue. The algorithm continues the breadth-first
search until the queue is empty and returns the current maximum number of removed
checkers. The Python code to capture the most pieces in one move is depicted in Code
6.11.
6.11 Capturing Maximum Checkers 237
Code 6.11 Python code to capture the most pieces in one move
1 ’’’
2 This function adds an item
3 to the end of the queue
4 ’’’
5 def enqueue(queue, item ) :
6 queue .append(item)
7
8 ’’’
9 This function removes and
10 returns the first item from the queue
11 ’’’
12 def dequeue(queue ) :
13 return queue .pop(0)
14
15 ’’’
16 This function checks if the queue is empty
17 ’’’
18 def is_empty(queue ) :
19 return len(queue) == 0
20
21 ’’’
22 This function finds the maximum number of
23 checkers that can be captured
24 ’’’
25 ’’’
26 by a single checker at position (x, y)
27 on an n x n checkerboard,
28 ’’’
29 ’’’
30 given the positions of the other
31 checkers in the set ‘pieces‘,
32 ’’’
33 ’’’
34 and the number of removed
35 checkers so far ‘removed‘.
36 ’’’
37 def Capturing_Max_Checkers(n, x, y, pieces , removed=0):
38 ’’’
39 We use a set called ‘visited‘
40 to keep track of the states
41 ’’’
42 visited = set ()
43 ’’’
238 6 Game
Chess is a sport that is familiar to everyone, or at the very least, has been heard of.
However, have you ever pondered the question of how the game would progress if
only the rook pieces were present on the board? Consider an n − by − n chessboard
with a selection of rook pieces placed upon it, some of which belong to the same side
as the friend player, and some of which belong to the opposing side. The rook pieces
are permitted to move either horizontally or vertically, and the chessboard spans from
square (0, 0) to (n − 1, n − 1). The objective of this challenge is to determine the
number of safe squares on the board for friend rooks. For some inputs, the expected
outputs are illustrated in Table 6.12.
Algorithm
It takes three inputs: an integer n representing the size of a square chessboard, a list
of tuples f riend_r ooks representing the positions of friendly rooks on the board,
and a list of tuples enemy_r ooks representing the positions of enemy rooks on the
board. It returns an integer representing the number of safe squares on the board. In
the first step, a board of size n ∗ n is created, with all squares initialized to zero to
signify that they are empty. Friend’s pieces are then placed on the board represented
by the value 1, while enemy pieces are represented by −1. In the next step, the safety
of each square is checked by examining its surrounding squares in the left, right, up,
and down directions. If a square is safe from all these directions, meaning it does
not contain an enemy piece, or it contains a friend’s piece, or it is empty, then it
is considered a safe square. The counter variable Sa f e S quar es is incremented by
one for each safe square encountered. Finally, in the last step, the function returns
Sa f e S quar es, which represents the number of safe squares on the board for the
friend’s pieces.
The Python code to return the number of safe squares for friend rooks is depicted
in Code 6.12.
Table 6.12 The expected outputs for certain inputs for determining the number of safe squares on
the board for friend rooks
n,friends,enemies Expected output
22,[(11, 7), (2, 4), (15, 7)], [(10, 20), (18, 12)] 397
9, [ (5,5)], [(2,5), (1,3)] 52
4, [ (2,2)], [(2,1)] 10
7, [ (2,2)], [(2,1),[6,4],[6,3]] 22
6.12 Safe Rooks with Friends 241
Code 6.12 Python code to return the number of safe squares for friend rooks
1 def Safe_rooks_with_friends(n, friend_rooks , enemy_rooks) :
2 # Initialize the chessboard
3 chess = [[0] ∗ n for _ in range(n)]
4 # Place rooks on the board
5 for x, y in friend_rooks + enemy_rooks:
6 value = 1 i f (x, y) in friend_rooks else −1
7 chess[x][y] = value
8
9 # Count safe squares
10 safe_squares = 0
11 for i in range(n) :
12 for j in range(n) :
13 i f chess[ i ][ j ] != 0:
14 continue # Skip occupied squares
15
16 # Check if the square is safe
17 is_safe = True
18 for k in range( j − 1, −1, −1): # Check left
19 i f chess[ i ][k] == −1:
20 is_safe = False
21 break
22 e l i f chess[ i ][k] == 1:
23 break
24 for k in range( j + 1, n) : # Check right
25 i f chess[ i ][k] == −1:
26 is_safe = False
27 break
28 e l i f chess[ i ][k] == 1:
29 break
30 for k in range( i + 1, n) : # Check down
31 i f chess[k][ j ] == −1:
32 is_safe = False
33 break
34 e l i f chess[k][ j ] == 1:
35 break
36 for k in range( i − 1, −1, −1): # Check up
37 i f chess[k][ j ] == −1:
38 is_safe = False
39 break
40 e l i f chess[k][ j ] == 1:
41 break
42
43 i f is_safe :
242 6 Game
Crag score refers to a type of dice game where, during their turn, the player rolls
three dice simultaneously to obtain a score. The objective of this challenge is to
determine and return the highest possible score from the three given dice. The rules
specified for this challenge are illustrated in the below table. If the obtained score does
not correspond to any category in below table, then the sum of the most frequently
occurring number should be returned as the score. Write a function that as input,
takes the outcome of the first three rolls, and returns the highest possible score.
For some inputs the expected outputs are illustrated in Table 6.13.
Table 6.13 The expected outputs for certain inputs for determining the highest score in crag game
Dice Expected output
[3,2,1] 20
[4,4,4] 25
[6,6,6] 25
[1,3,6] 6
6.13 Highest Score in Crag Score 243
Algorithm
It first creates two arrays, index and Sum_o f _each_N umber , both with a size of 6.
The index array is used to keep track of the number of times each possible number
appears in the dice list, while the Sum_o f _each_N umber array is used to store the
sum of each number in the dice list given based on its index. It then loops through
the first three items in the dice list, updating the index and Sum_o f _each_N umber
arrays accordingly. Next, it uses a series of if-else statements to check for various
combinations of numbers in the dice list that correspond to specific scoring rules. If a
match is found, the score is updated accordingly. If no matching condition is found,
it returns the sum of the most frequent numbers in the dice list. The Python code to
return the highest possible score in the crag dice game is depicted in Code 6.13.
Code 6.13 Python code to return the highest possible score in crag dice game
1 def Highest_Score_in_Crag_Score( dice ) :
2 ’’’
3 Defining an array with size 6,
4 as each dice is consisted of six numbers.
5 ’’’
6 index = [0]∗6
7 # Sum of each number in its index
8 Sum_of_each_Number = [0]∗6
9 Score = 0
10 for item in range(3):
11 index[ dice [item]−1] = index[ dice [item]−1]+1
12
13 Sum_of_each_Number[ dice [item] −1] = \
14 Sum_of_each_Number[ dice [item]−1]+dice [item]
15 ’’’
16 According to the defined rules, the following
17 if and else are defined.
18 ’’’
19 # Crag
20 i f (index[0] == 1 and index[5] == 2)\
21 or (index[2] == 1
22 and index[4] == 2) or \
23 (index[4] == 1 and index[3] == 2):
24 Score = 50
25 # Three-Of-A-Kind
26 e l i f (index[0] == 3 \
27 or index[1] == 3 or index[2] == 3 or
28 index[3] == 3 or index[4] == 3\
29 or index[5] == 3):
30 Score = 25
31 # Thirteen
244 6 Game
This challenge is similar to the previous one, such that instead of a single roll, multiple
rolls are given, where each roll is the outcome of three dice, and there is a constraint
that a category can not be visited more than once. Write a function that as input, takes
the outcome of the multiple rolls, and returns the highest possible score, otherwise,
returns zero. For some inputs, the expected outputs are illustrated in Table 6.14.
6.14 Optimal Crag Score with Multiple Rolls 245
Table 6.14 The expected outputs for certain inputs for obtaining the highest score in optimal crag
score with multiple rolls
Rolls Expected output
[(3, 3,3), (2, 5, 5), (1, 5, 6), (2,3,3)] 47
[(1,4,6), (2, 3, 5), (1, 5, 1)] 14
[(1,1,1), (4,3,6)] 51
Algorithm
The algorithm is the same as the crag dice game but there are significant differences.
It take multiple rolls as input. The first step in this algorithm is to generate all possible
combinations of the given rolls. Next, it iterates over each combination and checks
each ‘dice’ in the combination against a set of rules to determine its score. The rules
are provided in the previous section. The categor y_is_used list is used to keep
track of which rules have already been applied to the current combination. If a rule
has already been applied, it cannot be used again for the same combination. The
score for each ‘dice’ is determined based on which rule it satisfies. If a dice does
not satisfy any of the rules, then its score is the sum of its values (the most repeated
one). The total score for the combination is the sum of the scores. Finally, it returns
the maximum score across all combinations. The Python code to return the highest
possible score in the optimal crag dice game is depicted in Code 6.14.
Code 6.14 Python code to return the highest possible score in optimal crag dice game
1 ’’’
2 This function generates all
3 possible combinations of n rolls
4 ’’’
5 def generate_combinations( rolls , n) :
6 i f n == 0:
7 return [ [ ] ]
8 else :
9 combinations = []
10 for i in range(len( rolls ) ) :
11 sub_combinations =\
12 generate_combinations( rolls , n−1)
13 for combination in sub_combinations :
14 i f i not in combination :
15 combinations .append([ i ]+combination)
16 return combinations
17
18 ’’’
19 This function calculates the optimal
20 crag score given a list of rolls
21 ’’’
246 6 Game
67 index[4] == 3 or index[5] == 3) \
68 and not category_is_used [2]:
69 Desired_Score = 25
70 category_is_used[2] = True
71 #246
72 e l i f (index[1] == 1 and index[3] == 1
73 and index[5] == 1) \
74 and not category_is_used [3]:
75 Desired_Score = 20
76 category_is_used[3] = True
77 #456
78 e l i f (index[3] == 1 and index[4] == 1
79 and index[5] == 1) and not \
80 category_is_used [4]:
81 Desired_Score = 20
82 category_is_used[4] = True
83 #123
84 e l i f (index[0] == 1 and index[1] == 1
85 and index[2] == 1) and not \
86 category_is_used [5]:
87 Desired_Score = 20
88 category_is_used[5] = True
89 #135
90 e l i f (index[0] == 1 and index[2] == 1
91 and index[4] == 1) and not \
92 category_is_used [6]:
93 Desired_Score = 20
94 category_is_used[6] = True
95
96 else :
97 temp_index = 0
98 for i in range(6):
99 i f Desired_Score \
100 < Sum_of_each_Number[ i ] \
101 and not category_is_used[6+i ] :
102 temp_index = i
103 Desired_Score =\
104 Sum_of_each_Number[ i ]
105 category_is_used[6+temp_index]=True
106 points .append(Desired_Score)
107 result .append(sum( points ))
108 try :
109 return max( result )
110 except :
111 return 0
Chapter 7
Count
This chapter talks about 8 count-based problems. These challenges are explained
with some examples and then programmed in Python. The problems are listed as
follows:
1. Counting the number of carries when addition two given numbers
2. Counting the number of animals that are growling animals
3. Counting the number of consecutive summers for a polite number
4. Counting the occurrence of each digit and read it aloud
5. Counting the number of maximal layers on two-dimensional plane
6. Troika counter in positive integers
7. Counting the number of disks that are intersected.
When adding two or more digits, a carry occurs if the result of the addition exceeds
the largest number that the system can represent. This challenge requires counting the
number of carries that occur when two numbers are added together. To accomplish
this, you need to write a function that takes two positive integers, ‘a’ and ‘b’, as
input and returns the number of carries. For some inputs, the expected outputs are
illustrated in Table 7.1.
Algorithm
It is used two algorithm for counting the number of carries. The first calls a recursive
algorithm (get_digit_sum_r ecur sive) inside it. The recursive algorithm computes
the sum of given digits of a, b, and a + b. In fact, it repeatedly removes the last digit
of the number using integer division (n//10) and adds it to the sum until there are
no more digits left. Th recursive algorithm has the following steps.
© The Author(s), under exclusive license to Springer Nature Switzerland AG 2024 249
H. Izadkhah and R. Behzadidoost, Challenging Programming in Python: A Problem
Solving Perspective, https://doi.org/10.1007/978-3-031-39999-2_7
250 7 Count
15 return number % 10 + \
16 get_digit_sum_recursive (number / / 10)
17
18 ’’’
19 Counting the number of carries that
20 occur when adding two numbers
21 ’’’
22 def count_carries (num1, num2) :
23 # Compute the sum of digits of num1
24 digit_sum_num1 = get_digit_sum_recursive (num1)
25 # Compute the sum of digits of num2
26 digit_sum_num2 = get_digit_sum_recursive (num2)
27 # Compute the sum of digits of num1+num2
28 digit_sum_num1_num2 = get_digit_sum_recursive
29 (num1 + num2)
30 ’’’
31 The total number of carries is equal to this
32 ’’’
33 return (digit_sum_num1 + digit_sum_num2\
34 − digit_sum_num1_num2) / / 9
There are animals that see ‘cat and ‘dog facing left, and see ‘tac and ‘god facing
right. The animals are to be growling if they see strictly more dogs than cats on the
right or left. For example, if cd=[‘god , ‘cat , ‘cat , ‘tac , ‘tac , ‘dog , ‘cat , ‘god ]
be the given cats and dogs, count the number of animals is growling. In cd, it colorized
‘cat and ‘tac that there are more dogs than cats. Write a function that as input takes
a list of animals and returns the number of animals that are growling. For some inputs,
the expected outputs are illustrated in Table 7.2.
Algorithm
It iterates over each animal in the ‘animals’ list given and checks if it is a cat, dog,
tac, or god. The algorithm has the following steps.
1. It takes list animals as input.
2. Initialize a variable num_gr owler s to keep track of the number of growlers seen
so far.
3. Initialize a variable curr ent_animal_index to zero to keep track of the current
animal being checked.
4. While there are still animals left to check (i.e., curr ent_animal_index is less
than of length of animals:
a. If the current animal is a cat or dog, then count the number of cats and dogs
seen before it in the list. If there are more dogs than cats, then increment
num_gr owler s.
b. If the current animal is a tac or god, then count the number of cats and
dogs seen after it in the list. If there are more dogs than cats, then increment
num_gr owler s.
c. Move on to the next animal in the list.
5. Return the total number of growlers found.
The Python code for returning and counting the number of animals that are growl-
ing is depicted in Code 7.2.
Code 7.2 Python code for returning and counting the number of animals are growling
1 def Count_the_Growl_of_Animals(animals ) :
2 # initialize the number of growlers to zero
3 num_growlers = 0
4 # initialize the index of the current animal to zero
5 current_animal_index = 0
6 # while there are still animals left to check
7 while current_animal_index < len (animals ) :
8 # if the current animal is a cat or a dog
9 i f animals[current_animal_index] in ["cat" , "dog" ] :
10 ’’’
11 initialize the number of cats seen
12 so far to zero
13 ’’’
14 num_cats = 0
15 ’’’
16 initialize the number of dogs seen
17 so far to zero
18 ’’’
19 num_dogs = 0
20 ’’’
21 start checking animals
7.2 Counting Growl of Animals 253
In the domain of number theory, a positive integer that can be expressed as the sum of
two or more consecutive numbers is referred to as a polite number. On the other hand,
a positive integer that cannot be expressed in this manner is categorized as an impolite
number. It is important to note that both impolite and polite numbers are considered
natural numbers. This challenge is aimed to count the number of ways a number
can be expressed as consecutive positive integers. For example, the consecutive
positive integers for 42 are (a) 3 + 4 + 5 + 6 + 7 + 8 + 9, (b) 9 + 10 + 11 + 12,
(c)13 + 14 + 15, and (d) 42, or for 3, the consecutive positive integers are 2 + 1 and
3. Write a function that takes a positive integer n and returns the number of ways
a number can be expressed as consecutive positive integers. For some inputs, the
expected outputs are illustrated in Table 7.3.
7.4 Counting Occurrence of Each Digit 255
Algorithm
The algorithm will count the number of odd divisors of ‘n’, which is equivalent to
the number of ways in which ‘n’ can be expressed as a sum of consecutive positive
integers.
1. Take a positive integer ‘n’ as input.
2. Initialize a variable called ‘NumberofPolites’ to 0.
3. Use a loop to iterate over the range ‘1’ to ‘n+1’.
4. For each integer ‘i’ in the loop:
a. Check if ‘n’ is divisible by ‘i’ and ‘i’ is odd.
b. If both conditions are satisfied, increment the ‘NumberofPolites’ variable by
1.
5. Return ‘NumberofPolites’ as the output.
The Python code for returning and counting the number of consecutive summers is
depicted in Code 7.3.
Code 7.3 Python code for returning and counting the number of consecutive summers
1 def count_consecutive_summers(n) :
2 NumberofPolites = 0
3 for i in range(1 , n + 1):
4 i f n % i == 0 and i % 2 == 1:
5 NumberofPolites += 1
6 return NumberofPolites
The for loop iterates over all integers from 1 to n+1. The if statement checks if
the current integer ‘i’ is a divisor of n and whether it is odd or not. If both conditions
are satisfied, then the counter variable N umber o f Polites is incremented by 1.
Therefore, at the end of the loop, the value stored in N umber o f Polites represents
the total count of odd divisors of n.
Algorithm
It takes a list of digits as input and iterates through it, maintaining a count of con-
secutive identical digits using a variable named count. When a different digit is
encountered, it appends the count and digit to a list named ‘orders’ and resets the
count to 1. Finally, it returns a string representation of the elements in the ‘orders’ list.
The Python code to read aloud each digit is depicted in Code 7.4.
Code 7.4 Python code to read aloud each digit
languagelanguage
1 def Count_occurrence_of_each_digit ( digits ) :
2 orders = []
3 count = 1
4 previous_digit = digits [0]
5
6 ’’’
7 Iterate through the digits and
8 count the occurrence of each digit
9 ’’’
10 for current_digit in digits [ 1 : ] :
11 i f current_digit == previous_digit :
12 count += 1
13 else :
14 ’’’
15 Append the count of the previous digit
16 and the digit itself to the result
17 ’’’
18 orders .append( s t r (count ))
19 orders .append( previous_digit )
20 count = 1
21 previous_digit = current_digit
22
23 ’’’
24 Append the count of the last digit
25 and the digit itself to the result
26 ’’’
27 orders .append( s t r (count ))
28 orders .append( previous_digit )
29 return ’ ’ . join ( orders )
7.5 Counting Maximal Layers 257
On the two-dimensional plane, a point (x1 ,y1 ) dominates (x2 ,y2 ), if x1 >x2 and y1 >y2 .
If a point is not dominated by all points, the point is considered a maximal one, where
on the two-dimensional plane there can be any number of points that form a maximal
layer each time. This challenge is aimed to count the number of maximal layers. For
example, if points = [(1, 5), (3, 10), (2, 1), (9, 2)] be the given input, count the
number of maximal layers. From left to right the input is traversed, (1, 5) is not a
maximal one, because it is dominated by (3, 10), 3 is greater than 1 and 10 is greater
than 5. The next considered point from left to right is (3, 10), it is a maximal one,
because for (1, 5) and (3, 10), 1 is not greater than 3, and 5 is not grater than 10,
and for (2, 1) and (3, 10), 2 is not greater than 3, and 1 is not grater than 10, and for
(9, 2) and (3, 10), 9 is greater than 3, but 2 is not grater than 10. The next considered
one is (2, 1) and is not a maximal one, because it is dominated by (3, 10), and (9, 2)
is a maximal one, because alike (3, 10) it is not dominated by any point. Therefore,
for points = [(1, 5), (3, 10), (2, 1), (9, 2)] there are two maximal layers that one
is (10, 3) and another is (9, 2). Write a function that as input takes a list of points
and returns the number of maximal layers. For some inputs, the expected outputs are
illustrated in Table 7.5.
Algorithm
Let points be the given input, layerCounter be to enumerate the maximal layers.
It loops through the points in the list and checks if each point is maximal (i.e., if
there are no other points with greater x and y coordinates). If a point is maximal, it
is added to a list of maximal points. Once all maximal points have been identified,
the function increments the layerCounter and removes the maximal points from
the original list. The loop continues until there are no more points left in the list, and
the final layer count is returned. The Python code to count the number of maximal
layers is depicted in Code 7.5.
Code 7.5 Python code to count the the number of maximal layers
1 def count_maximal_layers_in_points ( points_list ) :
2 # Initialize layer counter to 0
3 layer_count = 0
4
5 # Loop until points_list becomes empty
258 7 Count
6 while points_list :
7 # Find all maximal points in the list
8 maximal_points = []
9 for point in points_list :
10 is_maximal = True
11 for other_point in points_list :
12 i f other_point [0] > point [0] \
13 and other_point [1] > point [1]:
14 is_maximal = False
15 break
16 i f is_maximal:
17 maximal_points .append( point )
18
19 ’’’
20 Increment layer_count by 1 if
21 there are any maximal points
22 ’’’
23 i f maximal_points :
24 layer_count += 1
25
26 ’’’
27 Remove all maximal points
28 from the original list
29 ’’’
30 for point in maximal_points :
31 points_list .remove( point )
32
33 # Return the number of maximal layers
34 return layer_count
Algorithm
The Python code to count the number of dominator numbers is depicted in Code 7.6.
Code 7.6 Python code to count the the number of dominator numbers
1 #Reverse the input
2 def reverse_list ( l s t ) :
3 ’’’
4 create an empty list to
5 store the reversed elements
6 ’’’
7 reversed_lst = []
8 ’’’iterate over the indices of
9 the list in reverse order
10 ’’’
11 for i in range( len ( l s t )−1, −1, −1):
12 reversed_lst .append( l s t [ i ])
13 # return the reversed list
14 return reversed_lst
15 """
16 Counts the number of dominators
17 in a list of integers.
18 """
19 def Counting_Dominator_Numbers(items ) :
20
21 # if the list is empty, return 0
22 i f not items :
23 return 0
260 7 Count
24
25 ’’’
26 In Python, -inf represents negative infinity.
27 ’’’
28 max_num = float ( ’−inf ’ )
29 # Initialize the dominator count to 0
30 dominator_count = 0
31 # iterate over the reversed list of items
32 for num in reverse_list (items ) :
33 ’’’
34 if the current number is greater than
35 the maximum number seen so far
36 ’’’
37 i f num > max_num:
38 # update the maximum number
39 max_num = num
40 # increment the dominator count
41 dominator_count += 1
42 # return the dominator count
43 return dominator_count
Let items be a list of numbers such that positions i < j < k in items make a
troika if items[i] == items[ j] == items[k], and j − i == k − j. For example,
if items = [42, 9, 42, 42, 42, 103] is the given input, count the number of troikas. In
the 0th position, 2th position, and 4th position, there are 42, 42, and 42, respectively,
where 2 − 0 =4 − 2, so 2 = 2. In the previous step, one Troika is found, and another
Troika is in the 2th position, 3th position, and 4th position, because 3 − 2 =4 − 3,
so 1 = 1. Therefore two Troikas are found. Write a function that as input takes a list
of positive and negative integers and returns the number of troikas. The expected
outputs are illustrated in Table 7.7 for some inputs.
Algorithm
Let T r oikaCounter be to enumerate the number of troikas, and items be the given
numbers. To satisfy condition j − i == k − j, it is utilized condition items[i] ==
items[ j] == items[2 ∗ j − i], and for each i in range 0 to |items|, and for each j
in range i + 1 to |items|, if condition items[i] == items[ j] == items[2 ∗ j − i]
is satisfied (2 ∗ j − i determines 3th position), the T r oikaCounter is incremented
by one. Now, T r oikaCounter is the number of troikas. The Python code to count
the number of troikas is depicted in Code 7.7.
Code 7.7 Python code to count the the number of troikas
1 def TroikaCounter(items ) :
2 TroikaCounter = 0
3 for i in range( len (items ) ) :
4 for j in range( i + 1, len (items ) ) :
5 k = 2∗j − i
6 i f k > ( len (items)−1):
7 pass
8 else :
9 i f items[ i ] == items[ j ] == items[k] :
10 TroikaCounter += 1
11 return TroikaCounter
On the two dimensional plane, there are disks as (x1, y1, r 1) and (x2, y2, r 2), where
(x, y) is the center point and r is the radius of the disks such that if Pythagorean
inequality (x2 − x1) ∗ ∗2 + (y2 − y1) ∗ ∗2 <= (r 1 + r 2) ∗ ∗2 satisfies, two disks
(x1, y1, r 1) and (x2, y2, r 2) have intersection. The power in Python is shown with
∗∗. It should be noted that the formula just works for the integers. In this challenge,
the coordinates of the center and the radius of the disks in a list are given, and the
task is to write a function that returns the pair of disks that intersect at least at one
point. For some inputs, the expected outputs are illustrated in Table 7.8.
Algorithm
To solve this challenge the sweep line algorithm is utilized. The sweep line algorithm
is a popular technique used in computational geometry to solve various problems
related to geometric objects’ arrangement and intersection. By sweeping a line or
plane across a set of objects, it enables the efficient detection of intersections, over-
laps, and other geometric properties. The number of comparisons of the circles is
n×n−1
2
, where it compares all circles and consequently increases the number of com-
parisons and the execution time. To reduce the number of comparisons especially
when the two circles have a far position, the sweep line algorithm is used, it is utilized
to compute the active space. In the active space, the intersection of the circles is more
frequent. Each disk enters the active space when the vertical line than to the x-axis
enters space (x − r ) and exits from the active space when vertical line leave (r + x).
The Python code to count the number of overlapping disks is depicted in Code 7.8
Code 7.8 Python code for counting the overlapping disks
1 def Counting_Intersected_Disks( disks ) :
2 # Sort disks
3 active_disks = sorted ( [ (x − r , x + r , x, y, r )
4 for x, y, r in disks ])
5
6 # I n i t i a l i z e count of overlapping disks to zero
7 count = 0
8
9 ’’’
10 Iterate over pairs of disks
11 and count overlapping disks
12 ’’’
13 for i in range( len ( active_disks ) − 1):
14 # Start with the next disk after i
15 j = i + 1
16
17 # Check i f j intersects with i
18 while j < len ( active_disks ) \
19 and active_disks [ j ][0] <= active_disks [ i ][1]:
20 ’ ’ ’Calculate the distance between
21 the centers of i and j
22 ’’’
23 dx = active_disks [ i ][2]− active_disks [ j ][2]
24 dy = active_disks [ i ][3]− active_disks [ j ][3]
25 r_sum =active_disks [ i ][4]+ active_disks [ j ][4]
26
27 # Check i f i and j overlap
28 i f dx ∗∗ 2 + dy ∗∗ 2 <= r_sum ∗∗ 2:
29 count += 1
30
7.8 Counting Intersected Disks 263
This chapter discusses six miscellaneous problems. These challenges are elucidated
with illustrative examples and subsequently implemented using the Python program-
ming language. The problems are enumerated as follows:
This challenge involves a list of items with an even number of elements, and the goal
is to perform a perfect riffle shuffle on the items. In a perfect riffle shuffle, the list
is split into two equal halves, and the shuffle is performed by alternately taking one
element from each half. There are two types of perfect riffle shuffles: an out-shuffle,
where the first item of the first half is taken first, followed by the first item of the
second half, and so on until all items have been shuffled; and an in-shuffle, where the
first item of the second half is taken first, followed by the first item of the first half, and
so on until all items have been shuffled. For example, if the given items be items =
[19, 456, 3, 4, 5, 6, 64, 11], riffle items with out-shuffle order. Firstly, in the two
same-sized halves items is splitted, so p1 = [19, 456, 3, 4] and p2 = [5, 6, 64, 11],
and st is defined to store the outputs. It is the order of insertion of outputs in
storage, st = [19] → st = [19, 5] → st = [19, 5, 456] → st = [19, 5, 456, 6] →
st = [19, 5, 456, 6, 3] → st = [19, 5, 456, 6, 3, 64] → st = [19, 5, 456, 6, 3, 64, 4]
→ st = [19, 5, 456, 6, 3, 64, 4, 11]. So, [19, 5, 456, 6, 3, 64, 4, 11] is as the riffled
list. For the example above with in-shuffle order, the riffled list of items is st =
[5, 19, 6, 456, 64, 3, 11, 4]. The process to reach the answer are st = [5] → st =
© The Author(s), under exclusive license to Springer Nature Switzerland AG 2024 265
H. Izadkhah and R. Behzadidoost, Challenging Programming in Python: A Problem
Solving Perspective, https://doi.org/10.1007/978-3-031-39999-2_8
266 8 Miscellaneous Problems
Table 8.1 The expected outputs for certain inputs to make a perfect riffle
Items, out Expected output
[19, 456, 3, 4, 5, 6, 64, 11], True [19, 5, 456, 6, 3, 64, 4, 11]
[19, 456, 3, 4, 5, 6, 64, 11], False [5, 19, 6, 456, 64, 3, 11, 4]
[0, 7, 89, 654, 5, 0, 1, 7] [0, 5, 7, 0, 89, 1, 654, 7]
[5, 19] → st = [5, 19, 6] → st = [5, 19, 6, 456] → st = [5, 19, 6, 456, 64] → st =
[5, 19, 6, 456, 64, 3] → st = [5, 19, 6, 456, 64, 3, 11] → st = [5, 19, 6, 456, 64, 3,
11, 4]. Write a function that as the input, takes a list of items and boolean variable
and returns the riffled list of items as out-shuffle or in-shuffle. For some inputs, the
expected outputs are illustrated in Table 8.1.
Algorithm
Let items be a list of the given items, storage be to store the outputs, and outin be
a boolean, where if outin is T r ue, mean out-shuffle, else in-shuffle. The first half
is stored in par t1, and the second half is stored in par t2. The |items|1 is divided by
two, and is stored in hal f , and for w in |halves| if outin is equal to T r ue, par t1[w]
is stored into storage and then par t2[w] is stored into storage, else par t2[w] is
stored into storage and then par t1[w] is stored into storage. Now, storage is the
list of riffled items.
The Python code to make a perfect riffle in the list of items is depicted in Code
8.1.
Code 8.1 Python code to make a perfect riffle
1 def perfect_riffle (items , outin=True ) :
2 '''
3 out=True: out-shuffle
4 out=False: in-shuffle
5 '''
6 # to store the outputs
7 storage=[]
8 # Splitting into two same-sized halves
9 halves=int (len(items )/2)
10 totallength=int (len(items ))
11 # part1 is the first half
12 part1=items [0: halves ]
13 # part2 is the second half
14 part2=items[ halves : totallength ]
15 for w in range( halves ) :
16 # Making out-shuffle
17 i f outin==True:
Table 8.2 The expected outputs for certain inputs for calculating smaller coins
Amount, coins Expected output
583, [142, 73, 45, 17, 13, 7, 1] [142, 142, 142, 142, 13, 1, 1]
26, [142, 45, 7, 1] [7, 7, 7, 1, 1, 1, 1, 1]
174, [94, 73, 17, 13, 7, 4, 3, 1] [94, 73, 7]
1, [142, 3, 1] [1]
Algorithm
1. Let amount be the given amount and coins be the list of coins.
2. Initialize an empty list called ‘smallercoins’ to store the smaller coins that make
up the amount.
3. For each coin in the ‘coins’ list, repeat steps 4–6:
4. Check if the remaining ‘amount’ is greater than or equal to the current ‘coin’.
5. If the remaining ‘amount’ is greater than or equal to the current ‘coin’, subtract
the ‘coin’ from the ‘amount’ and add it to the ‘smallercoins’ list.
6. If the remaining ‘amount’ is less than the current ‘coin’, move on to the next coin
in the ‘coins’ list.
7. Once all coins have been checked, return the ‘smallercoins’ list containing the
smaller coins that make up the amount.
The Python code to change the monies into the smaller coins depicted in Code
8.3.
Code 8.3 Python code to change the monies into the smaller coins
1 def calculate_smaller_coins (amount, coins ) :
2 # Create an empty list to store the smaller coins
3 smallercoins = []
4 # Loop through each coin in the list of coins
5 for coin in coins :
6 '''Keep subtracting the coin value from the
7 amount until it becomes less than the coin value
8 '''
9 while amount >= coin :
10 '''
11 Add the coin value to the
12 list of smaller coins
13 '''
14 smallercoins .append(coin)
15 # Subtract the coin value from the amount
16 amount −= coin
17 # Return the list of smaller coins
18 return smallercoins
8.3 Keep Frequent Items at Most n 269
Table 8.3 The expected outputs for certain inputs for getting items whose frequency is at most n
Items, n Expected output
[4, 4, 4, 4, 4, 4], 4 [4, 4, 4, 4]
[4, 5, 1000, 1, 2, 3], 5 [4, 5, 1000, 1, 2, 3]
[0, 0, 0, 0, 2, 0, 0, 0,0], 5 [0, 0, 0, 0, 2, 0]
[1001,‘python’,1003,‘world’,1001,1001] [1001, ‘python’, 1003, ‘world’, 1001]
There is a list of items with an arbitrary length, that is aimed to generate a list of items
that just keep exactly the items whose frequencies are less than or equal to n, where
the positions in the new list are the same as the original list. For example, consider
if i = [‘Python’, 4, 99, ‘R’, 4, ‘43’, 123, 80, 99, ‘Python’, 4] be the given items and
n = 2, j = [‘Python’, 4, 99, ‘R’, 4, ‘43’, 123, 80, 99, ‘Python’] is the new list that just
keeps the items that their frequency is less than or equal with n. In list i, except for
4 that is repeated three times, all items are stored into list j, and as n = 2 so the last
4 is skipped, because 4 is repeated three times. Write a function that takes as input
a positive integer n and a list of items, and returns a list of items whose frequency
is at most n and whose order in the list is preserved. If n = 0, the function should
return an empty list. For some inputs, the expected outputs are illustrated in Table 8.3.
Algorithm
It takes items_list and max_ f r equency as inputs and initializes an empty list
top_ f r equency_items to store the items whose frequencies are less than or equal
to max_ f r equency. Then, it creates an empty dictionary with keys as the items
in the list and initializes their values to 0. It counts the frequency of each item in
the list by iterating over the list and incrementing the value of the corresponding
key in the dictionary. It then ensures that the frequency of each item is not greater
than the given max_ f r equency by iterating over the dictionary and setting the
value to max_ f r equency if it exceeds it, and stores the resulting dictionary in
top_ f r equency_dict. Then, it iterates over items_list and adds each item to the
top_ f r equency_items list if its frequency in top_ f r equency_dict is greater than
0 and decrements its frequency in the dictionary by 1. After traversing all items
in items_list, top_ f r equency_items is returned as the output. The Python code
generates a new list that each item is repeated with a maximum of n depicted in Code
8.4.
Code 8.4 Python code to generate a new list that each item is repeated with a maximum of n
1 def calculate_item_frequency ( items_list , max_frequency ) :
2 '''
3 This function calculates the frequency of each
4 item in the given list and returns a dictionary
270 8 Miscellaneous Problems
There are two frogs and each frog has a starting point and a motion vector, and it
is represented by a 4-tuple as (sx, sy, dx, dy), where (sx, sy) denotes the starting
point that starts from zero, and (dx, dy) that is constant direction vector of move-
ment for each succeeding hop. Overall, each of the frogs is represented as follows:
Fr og1(sx1, sy1, d x1, dy1) Fr og2(sx1, sy1, d x1, dy1). This challenge is aimed to
obtain the time when both frogs jump to the same square. Write a function that as
input, takes the 4-tuple for each frog and the time when both frogs jump to the same
square, and if the two frogs never jump into the same square at the same time, None
is returned. For some inputs, the expected outputs are illustrated in Table 8.4.
8.4 Collision Time of Frogs 271
Table 8.4 The expected outputs for certain inputs for finding collision time of frogs
Frog1, frog2 Expected output
(562, −276, −10, 5), (49, −333, −1, 6) 57
(−3525, −877, 4, 1), (−4405, 2643, 5, −3) 880
(2726, −3200, −6, 7), (−2290, 2272, 5, −5) 456
(1591, −1442, −10, 9), (−329, −962, 2, 6) 160
Algorithm
It takes two arguments, frog1 and frog2, representing the positions and direction
vectors of two frogs. Based on the direction of the frogs, the algorithm applies
certain if rules to determine the time at which the two frogs will collide.
Code 8.5 Python code to compute and return the collision time of the given frogs
1 def Collision_time_of_frogs (frog1 , frog2 ) :
2 '''
3 Based on Frog1(sx1,sy1, dx1, dy1) and
4 Frog2(sx1, sy1, dx1, dy1), the positions
5 are filled.
6 '''
7 sx1=frog1[0]
8 sx2=frog2[0]
9 sy1=frog1[1]
10 sy2=frog2[1]
11 dx1=frog1[2]
12 dx2=frog2[2]
13 dy1=frog1[3]
14 dy2=frog2[3]
15
16 tx=0
17 ty=0
18 '''
19 1:
20 If the constant direction vector is equal to
21 (dx1==dx2==0 and dy1==dy2==0), it means
22 that it does not move at all:
23
24 If condition: If the starting position of
25 both frogs is the same, our output will
26 be equal to 0, that is, at time 0, these
27 two are standing in the square.
28
29 Else condition: If the starting position of
272 8 Miscellaneous Problems
75 tx=(sx2−sx1 ) / (dx1−dx2)
76 i f int ( tx)==tx and tx>0:
77 t=int ( tx )
78 else :
79 t=None
80 return t
81
82 '''
83 4:
84 If dx1!=dx2 is true (they are inequal):
85 1: if dy1!=dy2, tx and ty are computed.
86 1.2: If tx is equal to ty and their value
87 is non-decimal and also greater than 0,
88 tx is returned, otherwise, None is returned.
89 2: if dy1=dy2, tx is computed.
90 2.1: If tx is a non-decimal number and tx is
91 a positive number, tx is returned,
92 otherwise, None is returned.
93 '''
94 i f dx1!=dx2:
95 i f dy1!=dy2:
96 tx=(sx2−sx1 ) / (dx1−dx2)
97 ty=(sy2−sy1 ) / (dy1−dy2)
98 i f tx==ty and int ( tx)==tx and tx>0 :
99 t=int ( tx )
100 else :
101 t=None
102 return t
103 e l i f dy1==dy2:
104 tx=(sx2−sx1 ) / (dx1−dx2)
105 i f int ( tx)==tx and tx>0 and sy1==sy2:
106 t=int ( tx )
107 else :
108 t=None
109 return t
110
111 '''
112 5:
113 If dx1==dx2 (they are equal)
114 1: if dy1!=dy2, ty is calculated.
115 1.1: If ty is a non-decimal number
116 and ty is a positive number,
117 tx is returned, otherwise,
118 None is returned.
119 2: if dy1==dy2, None is returned.
274 8 Miscellaneous Problems
120 '''
121 i f dx1==dx2:
122 i f dy1!=dy2:
123 ty=(sy2−sy1 ) / (dy1−dy2)
124 i f int ( ty)==ty and ty>0 and sx1==sx2:
125 t=int ( ty )
126 else :
127 t=None
128 return t
129 e l i f dy1==dy2:
130
131 t=None
132 return t
133 return t
The Wythoff array is an infinite two-dimensional grid that is characterized by its first
row, which is identical to the Fibonacci sequence (1, 2, 3, 5, . . .). The array can be
defined as follows: Let pr denote the previous row, cr denote the current row, and a
and b denote the first and second elements of pr , respectively. The first element of
the next row (excluding the first row) is determined as the smallest number that does
not appear in any of the previous rows, and is denoted by c. The second element of
the next row is determined based on the following two conditions:
(1) If c − a = 2, then the value of the second element is b + 3. (2) If c − a = 2,
then the value of the second element is b + 5.
b + 3 i f c − a == 2 (equal with 2)
x= (8.1)
b + 5 i f c − a! = 2 (unequal with 2)
When the first two elements are specified, the same as in the Fibonacci sequence,
the next element is equal to the summation of the two previous numbers. For example,
let x1, x2, and x3 denote the first, second, and third rows of a Wythoff array.
x1 = 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,
x2 = 4, 7, 11, 18, 29, 47, 76, 123, 199,
x3 = 6, 10, 16, 26, 42, 68, 110, 178, 288.
Based on the preceding rows, the first element of x2 is 4, which is the smallest
number that does not appear in x1. To determine the second element of x2, we use
a = 1 and b = 2 from x1, and c = 4 from x2. We calculate c − a which is equal
to 4 − 1 = 3. Since 3 = 2, we use the formula b + 5 and obtain 7 as the value for
the second element of x2. After obtaining the first two elements of x2, we can con-
tinue the sequence using the Fibonacci sequence. For instance, the third position is
8.5 Positioning in Wythoff Array 275
obtained by adding 7 and 4 from the previous two positions, resulting in 11. Using
a similar approach, we can obtain x3 from x2. The objective of this challenge is
to find the position (index) of a given number n as a two-tuple (row, column). To
accomplish this, we need to write a function that takes a positive integer n as input
and returns its position as a two-tuple (row, column). For some inputs, the expected
outputs are illustrated in Table 8.5.
Algorithm
Let n be the given input. The algorithm starts by initializing the variables and sets. It
then iterates over the maximum number of columns allowed (n + 1) and generates
the two numbers in the current row based on the smaller and larger number from the
previous row. The smaller number is selected as the starting point, and the algorithm
iterates until an unvisited number is found. The next number based on provided rules
in Eq. 8.1 is computed. The algorithm then checks if the target number is in the
current row, then returns the position if found. If not found, the algorithm adds the
two new numbers to the set of visited numbers, checks the rest of the row for the
target number, and moves to the next row. This process repeats until the maximum
number of columns is reached. The Python code to return the position n in Wythoff
array is depicted in Code 8.6.
Code 8.6 Python code to return the position n in Wythoff array
1 def Positioning_in_Wythoff_Array(n) :
2 # Initialize variables and sets
3 visited_numbers = set ( [ ] )
4 current_row = 0
5 smaller_number , larger_number = −1, −1
6
7 '''
8 Iterate over the maximum number
9 of columns allowed
10 '''
11 for _ in range(n+1):
12
13 i f len(visited_numbers) == 0:
14 previous_number , last_number = 1, 2
15 else :
276 8 Miscellaneous Problems
16 '''
17 Choose the smaller number
18 as the starting point
19 '''
20 current_number = smaller_number
21
22 # Iterate until an unvisited number is found
23 while True:
24 i f current_number not in visited_numbers :
25
26 # Calculate the next number in the row
27 i f current_number − smaller_number==2:
28 next_number = larger_number + 3
29 else :
30 next_number = larger_number + 5
31
32 '''
33 Return the two numbers
34 for the next row
35 '''
36
37 previous_number , last_number =\
38 current_number , next_number
39 break
40
41 '''
42 Increment the current number
43 and try again
44 '''
45 current_number += 1
46
47 '''
48 Update the variables
49 for the next iteration
50 '''
51 smaller_number , larger_number =\
52 previous_number , last_number
53
54 '''
55 Check if the target number
56 is in the current row
57 '''
58 i f n == previous_number:
59 return (current_row , 0)
60 e l i f n == last_number :
8.6 Fractran Interpreter 277
61 return (current_row , 1)
62
63 '''
64 Add the two new numbers to
65 the set of visited numbers
66 '''
67 visited_numbers .add(previous_number)
68 visited_numbers .add(last_number)
69
70 '''
71 Check the rest of the row
72 for the target number
73 '''
74 column_number = 2
75 while last_number <= n:
76 new_number = previous_number + last_number
77
78 '''
79 Check if the target number
80 is in this column
81 '''
82 i f new_number == n:
83 return (current_row , column_number)
84
85 # Update the variables for the next iteration
86 previous_number = last_number
87 last_number = new_number
88 visited_numbers .add(new_number)
89 column_number += 1
90
91 # Move to the next row
92 current_row += 1
Table 8.6 The expected outputs for certain inputs for interpreting a Fractran program
n, program, itera Expected output
6, [(228, 131), (327, 158), (161, 394), (77, 425)], 4 [6]
2, [(345, 162), (108, 125), (90, 45), (293, 277)], 5 [2, 4, 8, 16, 32, 64]
10, [(1, 145), (7, 349), (156, 24)], 65 [10,65]
Algorithm
3. Next, it runs a loop for itera number of times, and within that loop, it runs another
loop to iterate over each fraction in the program list.
4. For each fraction, the algorithm multiplies the numerator by the first number in
the fraction, and multiplies the denominator by the second number in the fraction.
5. It then calculates the greatest common divisor (GCD) of the resulting numerator
and denominator using the gcd, and reduces the numerator and denominator by
dividing both by the GCD (GCD is used to simplify the fractions).
6. If the resulting denominator equals 1, the algorithm adds the numerator to the
r esult list (it is visited an integer number), updates the numerator and denominator
to the reduced values, and breaks out of the inner loop.
7. After the outer loop finishes running for the specified number of iterations, the
algorithm returns the list of generated values.
The Python code to interpret a Fractran program is depicted in Code 8.7.
Code 8.7 Python code to interpret a Fractran program
1 ''''
2 This function calculates the greatest
3 common divisor (GCD) of two numbers
4 '''
5 '''It takes two arguments a and b,
6 and returns their GCD.
7 '''
8 def gcd(a , b) :
9 i f b == 0:
10 return a
11 else :
12 return gcd(b, a % b)
13
14
15 '''It takes three arguments: n -
16 the initial value, program - a list of fractions,
17 and itera - the number of iterations to run.
18 '''
19 def Fractran_Interpreter (n, program, itera ) :
20 # Initialize the list with the initial value
21 result = [n]
22 numerator = n
23 denominator = 1
24 for i in range( itera ) :
25 for j in range(len(program) ) :
26 '''
27 # Multiply the numerator by the first
28 number of the fraction
29 '''
30 temp_num = program[ j ][0] * numerator
280 8 Miscellaneous Problems
31 '''
32 # Multiply the denominator by the
33 second number of the fraction
34 '''
35 temp_denom = program[ j ][1] * denominator
36 '''
37 # Calculate the GCD of the numerator
38 and denominator
39 '''
40 div = gcd(temp_num, temp_denom)
41 '''
42 Reduce the numerator by dividing
43 by the GCD
44 '''
45 temp_num //= div
46 '''
47 # Reduce the denominator
48 by dividing by the GCD
49 '''
50 temp_denom //= div
51 '''
52 # If the denominator is 1, add
53 the numerator to the result and
54 update the numerator and denominator
55 '''
56 i f temp_denom == 1:
57 result .append(temp_num)
58 numerator = temp_num
59 denominator = temp_denom
60 '''Stop checking fractions once one
61 is found that can be applied
62 '''
63 break
64 '''
65 # Return the list of values
66 generated by the program
67 '''
68 return result