Python Algorithms for Beginners – Searching, Sorting and Essential Problem-Solving Techniques
Learn Linear Search, Binary Search, Sorting Algorithms, Frequency Counting, Prime Numbers, Fibonacci, GCD, LCM, Palindromes and Anagrams with Python
Have you ever wondered how a computer finds a name in a list of thousands of students, arranges marks from highest to lowest, or checks whether a number is prime?
The secret lies in algorithms!
In this Python Pebbles tutorial, we will explore some of the most useful algorithms that every Class 9–12 student should understand. You will learn not only how to write the code but also how to think like a programmer.
1. What Is an Algorithm?
An algorithm is a step-by-step procedure used to solve a problem.
Think of an algorithm like a recipe. A recipe explains how to prepare a dish step by step. Similarly, an algorithm explains how to solve a programming problem step by step.
Example: Finding the Largest Number
Suppose we have these numbers:
numbers = [12, 45, 7, 89, 34]
We want to find the largest number.
Our algorithm is:
Assume the first number is the largest.
Compare it with every other number.
If a larger number is found, update the largest value.
Display the result.
Python program:
numbers = [12, 45, 7, 89, 34]
largest = numbers[0]
for number in numbers:
if number > largest:
largest = number
print("Largest number:", largest)
Output:
Largest number: 89
Python Pebble: Before writing code, explain the solution in simple steps. This makes programming easier and helps you find mistakes.
Part 1: Searching Algorithms
Searching means finding whether a particular value exists in a collection and, if it does, where it is located.
Imagine looking for your name in a class attendance list. The method you use depends on how the list is organized.
2. Linear Search
Linear Search checks each element one by one until the target is found or the list ends.
It works on both sorted and unsorted lists.
Example
numbers = [15, 28, 7, 42, 19]
target = 42
found = False
for i in range(len(numbers)):
if numbers[i] == target:
print("Found at index:", i)
found = True
break
if not found:
print("Number not found")
Output:
Found at index: 3
Remember that Python list indexing starts from 0.
How does it work?
For the list [15, 28, 7, 42, 19], searching for 42 follows these steps:
| Step | Value checked | Result |
|---|---|---|
| 1 | 15 | Not found |
| 2 | 28 | Not found |
| 3 | 7 | Not found |
| 4 | 42 | Found! |
Linear Search Using a Function
def linear_search(numbers, target):
for i in range(len(numbers)):
if numbers[i] == target:
return i
return -1
data = [10, 20, 30, 40, 50]
print(linear_search(data, 30))
print(linear_search(data, 90))
Output:
2
-1
Here, -1 indicates that the target was not found.
Time complexity: in the worst case, because every element may need to be checked.
When should you use Linear Search?
When the list is small.
When the data is not sorted.
When you need a simple search method.
3. Binary Search
Binary Search is a faster searching algorithm, but it requires the list to be sorted.
Instead of checking every element, it repeatedly divides the search area into two halves.
Imagine searching for a word in a dictionary. You would open the dictionary near the middle rather than reading every word from the beginning.
Example
Consider this sorted list:
numbers = [10, 20, 30, 40, 50, 60, 70]
We want to find 60.
Check the middle element:
40.Since
60is greater than40, ignore the left half.Check the middle of the remaining section.
Find
60.
Python Program
def binary_search(numbers, target):
low = 0
high = len(numbers) - 1
while low <= high:
mid = (low + high) // 2
if numbers[mid] == target:
return mid
elif numbers[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
data = [10, 20, 30, 40, 50, 60, 70]
print(binary_search(data, 60))
print(binary_search(data, 25))
Output:
5
-1
Linear Search vs Binary Search
| Feature | Linear Search | Binary Search |
|---|---|---|
| Data must be sorted? | No | Yes |
| Basic method | Check one by one | Divide the search range |
| Worst-case time | ||
| Best suited for | Small or unsorted data | Large, sorted data |
Python Pebble: Binary Search is powerful because each step removes approximately half of the remaining search area.
Part 2: Sorting Algorithms
Sorting means arranging data in a particular order, such as ascending or descending.
For example:
Before sorting: [45, 12, 89, 23, 7]
After sorting: [7, 12, 23, 45, 89]
Let's explore three classic sorting algorithms.
4. Bubble Sort
Bubble Sort compares adjacent elements and swaps them if they are in the wrong order.
After each complete pass through the list, the largest unsorted element moves to its correct position at the end.
Example
numbers = [5, 3, 8, 2]
for i in range(len(numbers)):
for j in range(0, len(numbers) - i - 1):
if numbers[j] > numbers[j + 1]:
numbers[j], numbers[j + 1] = (
numbers[j + 1], numbers[j]
)
print(numbers)
Output:
[2, 3, 5, 8]
Understanding the First Pass
Starting list:
[5, 3, 8, 2]
Compare 5 and 3, then swap:
[3, 5, 8, 2]
Compare 5 and 8. No swap is needed.
Compare 8 and 2, then swap:
[3, 5, 2, 8]
The largest value, 8, has moved to the end.
Optimized Bubble Sort
We can stop early if a complete pass makes no swaps.
def bubble_sort(numbers):
n = len(numbers)
for i in range(n):
swapped = False
for j in range(n - i - 1):
if numbers[j] > numbers[j + 1]:
numbers[j], numbers[j + 1] = (
numbers[j + 1], numbers[j]
)
swapped = True
if not swapped:
break
return numbers
print(bubble_sort([9, 4, 6, 2, 1]))
Output:
[1, 2, 4, 6, 9]
Worst-case time complexity: .
Use Bubble Sort to learn how comparisons, loops, and swaps work. For large real-world lists, Python's built-in sorting is generally a better choice.
5. Selection Sort
Selection Sort repeatedly finds the smallest element in the unsorted part of the list and places it at the beginning of that part.
Example
numbers = [29, 10, 14, 37, 13]
for i in range(len(numbers)):
min_index = i
for j in range(i + 1, len(numbers)):
if numbers[j] < numbers[min_index]:
min_index = j
numbers[i], numbers[min_index] = (
numbers[min_index], numbers[i]
)
print(numbers)
Output:
[10, 13, 14, 29, 37]
How does it work?
Find the smallest number in the entire list.
Place it at index
0.Find the smallest number in the remaining unsorted section.
Place it at index
1.Repeat until the list is sorted.
Worst-case time complexity: .
Key idea: Selection Sort selects the smallest remaining element on every pass.
6. Insertion Sort
Insertion Sort builds a sorted section one element at a time.
Think about arranging playing cards in your hand. You pick up one card and insert it into the correct position among the cards you are already holding.
Python Program
numbers = [8, 4, 6, 2, 5]
for i in range(1, len(numbers)):
key = numbers[i]
j = i - 1
while j >= 0 and numbers[j] > key:
numbers[j + 1] = numbers[j]
j -= 1
numbers[j + 1] = key
print(numbers)
Output:
[2, 4, 5, 6, 8]
How does it work?
Treat the first element as sorted.
Pick the next element as
key.Move larger elements one position to the right.
Insert the key into the empty position.
Continue until every element is processed.
Time complexity:
Best case: , when the list is already sorted.
Worst case: , when the list is in reverse order.
Compare the Three Sorting Algorithms
| Algorithm | Main idea | Worst-case time |
|---|---|---|
| Bubble Sort | Swap adjacent elements | |
| Selection Sort | Select the smallest remaining value | |
| Insertion Sort | Insert each value into the sorted section |
7. Python's Built-in sort()
You do not always need to write a sorting algorithm yourself. Python provides a highly optimized sorting method.
The sort() method changes the original list.
marks = [78, 92, 65, 88, 71]
marks.sort()
print(marks)
Output:
[65, 71, 78, 88, 92]
Sorting in Descending Order
marks = [78, 92, 65, 88, 71]
marks.sort(reverse=True)
print(marks)
Output:
[92, 88, 78, 71, 65]
8. Python's sorted() Function
The sorted() function returns a new sorted list and leaves the original collection unchanged.
numbers = [40, 10, 30, 20]
result = sorted(numbers)
print("Original:", numbers)
print("Sorted:", result)
Output:
Original: [40, 10, 30, 20]
Sorted: [10, 20, 30, 40]
Difference Between sort() and sorted()
| Feature | sort() | sorted() |
|---|---|---|
| Type | List method | Built-in function |
| Changes original list? | Yes | No |
| Returns | None | A new sorted list |
| Works with tuples? | No, not as a tuple method | Yes |
9. Custom Sorting
Sometimes we want to sort data according to a special rule.
For example, suppose we have student names and marks. We want to sort the students by marks in descending order.
students = [
("Aman", 85),
("Riya", 92),
("Karan", 78),
("Meena", 92)
]
students.sort(key=lambda student: student[1], reverse=True)
print(students)
Output:
[('Riya', 92), ('Meena', 92), ('Aman', 85), ('Karan', 78)]
Here:
student[0]represents the student's name.student[1]represents the student's marks.key=lambda student: student[1]tells Python to sort using marks.
Sorting by Name
students = [
("Aman", 85),
("Riya", 92),
("Karan", 78)
]
result = sorted(students, key=lambda student: student[0])
print(result)
Output:
[('Aman', 85), ('Karan', 78), ('Riya', 92)]
Python Pebble: Custom sorting is useful when working with student records, product prices, employee details, and competition results.
Part 3: Common Algorithms Every Student Should Know
10. Finding the Maximum and Minimum
Python provides max() and min() for finding the largest and smallest values.
numbers = [45, 12, 89, 23, 7]
print("Maximum:", max(numbers))
print("Minimum:", min(numbers))
Output:
Maximum: 89
Minimum: 7
Find Them Without Built-in Functions
numbers = [45, 12, 89, 23, 7]
largest = numbers[0]
smallest = numbers[0]
for number in numbers:
if number > largest:
largest = number
if number < smallest:
smallest = number
print("Maximum:", largest)
print("Minimum:", smallest)
Output:
Maximum: 89
Minimum: 7
This approach helps you understand how algorithms work internally.
11. Finding Sum and Average
The sum is the total of all values. The average is the sum divided by the number of values.
Python Program
marks = [80, 75, 90, 85, 70]
total = 0
for mark in marks:
total += mark
average = total / len(marks)
print("Total:", total)
print("Average:", average)
Output:
Total: 400
Average: 80.0
Python also provides sum():
marks = [80, 75, 90, 85, 70]
print(sum(marks))
print(sum(marks) / len(marks))
Output:
400
80.0
Always check that a list is not empty before calculating its average, because division by zero is not allowed.
12. Frequency Counting
Frequency counting tells us how many times each value appears in a collection.
Suppose we want to count the votes received by candidates.
votes = ["A", "B", "A", "C", "B", "A"]
frequency = {}
for vote in votes:
if vote in frequency:
frequency[vote] += 1
else:
frequency[vote] = 1
print(frequency)
Output:
{'A': 3, 'B': 2, 'C': 1}
A Shorter Method Using Counter
from collections import Counter
votes = ["A", "B", "A", "C", "B", "A"]
frequency = Counter(votes)
print(frequency)
print(frequency["A"])
Output:
Counter({'A': 3, 'B': 2, 'C': 1})
3
Where is frequency counting useful?
Counting votes.
Counting words in an article.
Analyzing examination scores.
Finding the most common item in a dataset.
13. Duplicate Detection
A duplicate is a value that appears more than once.
Example
numbers = [10, 20, 30, 20, 40, 10, 50]
seen = set()
duplicates = set()
for number in numbers:
if number in seen:
duplicates.add(number)
else:
seen.add(number)
print("Duplicates:", sorted(duplicates))
Output:
Duplicates: [10, 20]
How does it work?
seenstores values that have already appeared.If a value appears again, it is added to
duplicates.A set stores each distinct value only once.
For typical integer or string data, set membership checks are on average, so this is generally efficient.
14. Checking Prime Numbers
A prime number is a whole number greater than 1 that has exactly two positive divisors: 1 and itself.
Examples: 2, 3, 5, 7, 11, 13
Numbers such as 4, 6, 8, 9, 10 are not prime.
Python Program
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
print(is_prime(17))
print(is_prime(21))
Output:
True
False
Why do we check only up to the square root?
If a number has a factor greater than its square root, it must also have a corresponding factor smaller than its square root. Therefore, if no divisor is found up to the square root, the number is prime.
Python Pebble: The % operator gives the remainder. If n % i == 0, then i divides n exactly.
15. Generating Fibonacci Numbers
The Fibonacci sequence is a sequence in which each new number is the sum of the previous two numbers.
A common starting sequence is:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34
Python Program
n = 10
a = 0
b = 1
for i in range(n):
print(a, end=" ")
a, b = b, a + b
Output:
0 1 1 2 3 5 8 13 21 34
Understanding the Update
a, b = b, a + b
Python evaluates the right-hand side first, then assigns both values together.
This means:
The new
abecomes the oldb.The new
bbecomes the sum of the oldaandb.
This iterative approach avoids the repeated work of a simple recursive Fibonacci program.
16. Calculating Factorial
The factorial of a non-negative integer is the product of all positive integers up to that number.
It is represented by an exclamation mark.
By definition, .
Python Program
n = 5
factorial = 1
for i in range(1, n + 1):
factorial *= i
print("Factorial:", factorial)
Output:
Factorial: 120
Factorial Using a Function
def factorial(n):
if n < 0:
return None
result = 1
for i in range(1, n + 1):
result *= i
return result
print(factorial(5))
print(factorial(0))
print(factorial(-2))
Output:
120
1
None
The function returns None for negative input because factorial is not defined for negative integers in this context.
17. Finding GCD and LCM
What is GCD?
The Greatest Common Divisor (GCD) of two integers is the largest positive integer that divides both of them exactly.
For example, the GCD of 12 and 18 is 6.
What is LCM?
The Least Common Multiple (LCM) of two positive integers is the smallest positive integer divisible by both.
For example, the LCM of 12 and 18 is 36.
GCD Using Euclid's Algorithm
Euclid's algorithm repeatedly replaces a pair of numbers with the smaller number and their remainder until the remainder becomes zero.
def gcd(a, b):
while b != 0:
a, b = b, a % b
return abs(a)
print(gcd(12, 18))
print(gcd(48, 18))
Output:
6
6
LCM Using GCD
For positive integers and :
A Python implementation is:
def gcd(a, b):
while b:
a, b = b, a % b
return abs(a)
def lcm(a, b):
if a == 0 or b == 0:
return 0
return abs((a // gcd(a, b)) * b)
print("GCD:", gcd(12, 18))
print("LCM:", lcm(12, 18))
Output:
GCD: 6
LCM: 36
Python also provides math.gcd() and, in modern Python versions, math.lcm().
18. Checking Palindromes
A palindrome is a word, number, or sequence that reads the same forward and backward.
Examples:
madamlevel1211331
Python Program
text = "madam"
if text == text[::-1]:
print("Palindrome")
else:
print("Not a palindrome")
Output:
Palindrome
The expression text[::-1] creates a reversed copy of the string.
Palindrome Function
def is_palindrome(text):
text = text.lower()
return text == text[::-1]
print(is_palindrome("Madam"))
print(is_palindrome("Python"))
Output:
True
False
This version ignores letter case but not spaces or punctuation.
Challenge: Ignore Spaces and Punctuation
Can you modify the function so that a phrase such as "A man, a plan, a canal: Panama" is recognized as a palindrome?
Hint: Keep only alphanumeric characters using str.isalnum() before comparing the text with its reverse.
19. Checking Anagrams
Two words are anagrams if they contain exactly the same letters with the same frequencies, but in a different order.
Examples:
listenandsilentearthandheartraceandcare
Python Program
def are_anagrams(word1, word2):
word1 = word1.replace(" ", "").lower()
word2 = word2.replace(" ", "").lower()
return sorted(word1) == sorted(word2)
print(are_anagrams("listen", "silent"))
print(are_anagrams("hello", "world"))
Output:
True
False
The program:
Converts both words to lowercase.
Removes spaces.
Sorts the characters in each word.
Compares the sorted results.
Anagram Detection Using Frequency Counting
from collections import Counter
def are_anagrams(word1, word2):
word1 = word1.replace(" ", "").lower()
word2 = word2.replace(" ", "").lower()
return Counter(word1) == Counter(word2)
print(are_anagrams("earth", "heart"))
Output:
True
Frequency counting avoids sorting and is often a convenient way to compare character counts.
Part 4: Understanding Algorithm Efficiency
A program can produce the correct answer and still be inefficient when given a large amount of data.
Time complexity describes how the work performed by an algorithm grows as the input size increases.
Here is a beginner-friendly reference table.
| Complexity | Common example | General interpretation |
|---|---|---|
| Access a list element by index | Constant-time operation | |
| Binary Search | Grows slowly | |
| Linear Search | Work grows roughly with input size | |
| Efficient general-purpose sorting | Scales well for many large lists | |
| Basic Bubble Sort | Can become slow as input grows |
These are typical complexity descriptions; actual performance also depends on the data, implementation, and execution environment.
Why does it matter?
Suppose you have one million sorted numbers.
Linear Search may need to inspect up to one million elements.
Binary Search needs roughly 20 comparisons in the worst case for a list of that size.
That is why choosing the right algorithm matters.
Part 5: Mini-Projects for Practice
Project 1: Student Marks Analyzer
Goal: Analyze the marks of students in a class.
Your program should:
Store marks in a list.
Calculate the maximum and minimum marks.
Calculate the total and average.
Sort the marks in descending order.
Count how many students scored above 75.
Search for a particular mark.
Starter code:
marks = [78, 92, 65, 88, 92, 71, 56, 85]
print("Highest:", max(marks))
print("Lowest:", min(marks))
print("Average:", sum(marks) / len(marks))
print("Descending order:", sorted(marks, reverse=True))
above_75 = 0
for mark in marks:
if mark > 75:
above_75 += 1
print("Students scoring above 75:", above_75)
Expected output:
Highest: 92
Lowest: 56
Average: 78.375
Descending order: [92, 92, 88, 85, 78, 71, 65, 56]
Students scoring above 75: 5
Extension: Ask the user to enter a mark and use Binary Search to find it in a sorted list.
Project 2: Number Toolkit
Create a menu-driven program that allows a user to:
Check whether a number is prime.
Calculate factorial.
Generate Fibonacci numbers.
Check whether a number is a palindrome.
Find the GCD and LCM of two numbers.
Extension: Validate the user's input and allow the program to continue until the user selects Exit.
Project 3: Word Analyzer
Write a program that accepts a sentence and:
Counts the frequency of each word.
Identifies repeated words.
Finds the longest word.
Checks whether two entered words are anagrams.
Checks whether the sentence is a palindrome after ignoring spaces and punctuation.
Extension: Display the five most frequently used words.
Part 6: Practice Questions
Try these questions before looking for solutions.
A. Conceptual Questions
What is an algorithm? Give one real-life example.
Why must the input list be sorted before applying Binary Search?
What is the main difference between Bubble Sort and Selection Sort?
What is the difference between
list.sort()andsorted(list)?What does mean?
Why does Binary Search generally outperform Linear Search on large, sorted lists?
What is the purpose of the
keyparameter in Python's sorting functions?Why is a set useful for detecting duplicates?
B. Programming Challenges
Write a Linear Search function that returns the index of the first occurrence of a target.
Implement Binary Search and test it with both present and absent values.
Write Bubble Sort to arrange a list in descending order.
Implement Selection Sort without using
sort()orsorted().Write Insertion Sort and count how many shifts are performed.
Sort a list of names alphabetically using
sorted().Sort student records by marks in descending order and use names alphabetically to break ties.
Find the second-largest distinct number in a list.
Count the frequency of each character in a string.
Identify all duplicate values in a list.
Print all prime numbers between
1and100.Generate the first
nFibonacci numbers.Calculate factorial using iteration.
Find the GCD and LCM of two numbers.
Check whether a phrase is a palindrome after ignoring case, spaces, and punctuation.
Check whether two phrases are anagrams after ignoring case and spaces.
Build a menu-driven program that combines at least five of the algorithms in this article.
Quick Revision: Algorithms Cheat Sheet
| Problem | Useful approach |
|---|---|
| Search an unsorted list | Linear Search |
| Search a sorted list | Binary Search |
| Sort a list in Python | sort() or sorted() |
| Learn basic sorting logic | Bubble, Selection, Insertion Sort |
| Find maximum/minimum | max() / min() or a loop |
| Calculate total | sum() or accumulation |
| Count repeated values | Dictionary or Counter |
| Detect duplicates | Set |
| Test a prime number | Divisibility checks up to the square root |
| Generate Fibonacci numbers | Iterative updates |
| Calculate factorial | Multiplication loop |
| Find GCD | Euclid's algorithm |
| Find LCM | Use GCD |
| Check palindrome | Compare with reversed text |
| Check anagram | Compare sorted characters or frequencies |
Final Thoughts
Algorithms are the foundation of problem-solving in programming. Once you understand how searching, sorting, counting, and number-based algorithms work, you will be better prepared to solve school programming questions, build useful projects, and explore more advanced topics such as data structures, competitive programming, and artificial intelligence.
Remember: Do not just memorize the code. Understand the steps, test different inputs, and try to improve your solution.
Your next Python Pebble challenge: Pick one algorithm from this tutorial, write it without looking at the example, test it on at least three inputs, and explain its logic in your own words.
Keep coding, keep experimenting, and keep collecting Python Pebbles!