Searching Algorithms
Why this matters
Imagine you're scrolling through a giant Spotify playlist with hundreds of songs, looking for that one specific track by Taylor Swift that's stuck in your head. You don't know exactly where it is, so what do you do? You start at the top and check each song, one by one, until you find it. "Nope, not this one... not this one... ah, there it is!"
This simple, methodical process is something we do all the time. We do it when we're looking for a specific email in our inbox or trying to find a can of corn in a crowded pantry. In computer science, this fundamental technique has a name: linear search. It's our most basic, but incredibly reliable, tool for finding data. Today, we'll break down how to write it, how to apply it to different kinds of data, and how to avoid the common pitfalls.
Concept overview
flowchart TD
A[Start] --> B{Initialize index i = 0};
B --> C{Is i < array.length?};
C -- Yes --> D{Is array[i] == target?};
C -- No --> G[Return -1 (Not Found)];
D -- Yes --> E[Return i (Found)];
D -- No --> F{Increment i};
F --> C;
Core explanation
Hello everyone, I'm Saavi, and I'm glad you're here. Let's talk about one of the most fundamental ideas in programming: finding things.
At its heart, a linear search is exactly what it sounds like: you search for something by moving in a straight line from start to finish. It’s the "brute force" way of searching, but don't let that fool you—it's powerful and often the right tool for the job.
The Basic Idea: Searching a 1D Array
Let's stick with our analogy of finding a book on a single shelf. The shelf is our array, and the books are the elements. To find a specific book, you start at one end (usually the left, or index 0) and inspect each book until you find the one you want.
In code, this translates to a for loop that visits every index of the array.
Let's say we have an array of high scores from an arcade game and we want to find out if anyone scored exactly 5,000 points.
int[] scores = {1200, 4500, 3250, 5000, 2100};
int targetScore = 5000;
To perform a linear search, we'll:
- Start at the beginning of the array (
index 0). - Check if the element at the current index is our
targetScore. - If it is, we've found it! We can stop searching and report the index where we found it.
- If it's not, we move to the next index and repeat.
- If we get all the way to the end of the array and never find it, we can conclude the score isn't in our list.
Here’s what that looks like as a complete method:
/**
* Searches for a target value in an array of integers.
* @param arr The array to search through.
* @param target The value to search for.
* @return The index of the first occurrence of the target, or -1 if not found.
*/
public int linearSearch(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i; // Found it! Return the index and exit the method.
}
}
// If the loop finishes, we never found the target.
return -1;
}
The "Not Found" Case: A Critical Detail
Look closely at that code. The return -1; statement is outside the for loop.
// AVOID THIS COMMON MISTAKE!
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
} else {
return -1; // WRONG!
}
}
Why is this wrong? This code checks only the first element. If arr[0] isn't the target, it immediately returns -1 and stops, never checking the rest of the array. You can only be sure the item is missing after you've checked every single spot.
Think of it this way: you can't say your friend isn't at the party until you've scanned the whole room. You don't give up after looking at the first person by the door.
Searching from the Other End
The AP standards mention that a linear search can start from either end. To find the last occurrence of a value, or if you have a reason to believe your item is near the end, you can simply reverse the loop:
public int linearSearchFromEnd(int[] arr, int target) {
for (int i = arr.length - 1; i >= 0; i--) { // Start at the end, go backwards
if (arr[i] == target) {
return i; // Found the last (or first from the end) occurrence
}
}
return -1;
}
The logic is identical, just the direction of travel is different.
This also works for ArrayLists, you just use .size() and .get(i) instead of .length and arr[i]. The underlying algorithm is the same.
Stepping It Up: Linear Search on a 2D Array
What if your data isn't a simple list, but a grid? Think of a movie theater seating chart, a spreadsheet, or a bingo card. This is a 2D array.
To search a 2D array, you apply the same linear search logic, but you have to do it for each row. Imagine you're an usher looking for a dropped phone in a theater. You'd likely pick a row, walk down it checking every seat, and if you don't find it, you move to the next row and repeat.
This translates perfectly to a nested loop. The outer loop handles the rows, and the inner loop handles the columns (the seats in that row).
Let's say we have a 2D array representing a grid of lottery numbers, and we want to see if the number 7 is on the ticket.
int[][] lotteryTicket = {
{23, 4, 19, 42},
{11, 7, 33, 5},
{1, 15, 28, 3}
};
Here's how we'd search it:
/**
* Searches for a target value in a 2D integer array.
* @param grid The 2D array to search.
* @param target The value to search for.
* @return true if the target is found, false otherwise.
*/
public boolean searchGrid(int[][] grid, int target) {
// Outer loop iterates through each row
for (int i = 0; i < grid.length; i++) {
// Inner loop iterates through each element in the current row
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == target) {
return true; // Found it! We can stop immediately.
}
}
}
// If we get through ALL rows and ALL columns, it's not here.
return false;
}
Notice here we return a boolean—true or false. This is common for 2D array searches when we just need to know if the item exists. If we needed to know where it was, we might return an array like {i, j} representing the row and column. But for now, a simple "yes" or "no" is perfect.
The core idea is the same: check every spot. For a 2D array, that just means checking every spot in row 0, then every spot in row 1, and so on, until you find your target or run out of spots.
See it in action
Worked examples
Let's walk through a few examples to make this concrete.
Finding a Value in a 1D Array
Problem: You are given an array of jersey numbers for a basketball team. Write a method to find the index of the player with jersey number 23. If no player has that number, return -1.
int[] jerseys = {10, 30, 23, 5, 12};
Step-by-Step Solution:
- 1Set up the searchOur method
linearSearch(jerseys, 23)will start aforloop withi = 0. - 2Iteration 1 (i = 0)
jerseys[0]is10.- Is
10 == 23? No. The loop continues.
- 3Iteration 2 (i = 1)
jerseys[1]is30.- Is
30 == 23? No. The loop continues.
- 4Iteration 3 (i = 2)
jerseys[2]is23.- Is
23 == 23? Yes! We found it. - The
ifcondition is true, so the method executesreturn i;. The current value ofiis2. - The method immediately stops and returns
2. The loop does not continue to check5and12.
What if we searched for 45?
The loop would run through all 5 elements. None would match. The loop would finish, and the line return -1; after the loop would execute.
Searching a 2D Array for Existence
Problem: A coffee shop in Seattle tracks its daily sales of different drinks in a 2D array. Each row is a different day, and each column is a different drink (latte, cappuccino, etc.). Find out if they ever sold exactly 150 of any drink on any day.
int[][] sales = {{145, 201, 88}, {120, 150, 95}, {162, 198, 101}};
Step-by-Step Solution:
- 1Set up the nested loopOur
searchGrid(sales, 150)method begins. The outer loop starts with rowi = 0. - 2Outer Loop (i = 0)
- The inner loop for the columns begins with
j = 0. j = 0: Issales[0][0](which is145) equal to150? No.j = 1: Issales[0][1](which is201) equal to150? No.j = 2: Issales[0][2](which is88) equal to150? No.- The inner loop for row 0 finishes.
- The inner loop for the columns begins with
- 3Outer Loop (i = 1)
- The outer loop increments to
i = 1. The inner loop restarts for this new row. j = 0: Issales[1][0](which is120) equal to150? No.j = 1: Issales[1][1](which is150) equal to150? Yes!- The
ifcondition is met. The method executesreturn true;. - The entire method terminates, returning
true. It never checks the rest of row 1 or any of row 2.
- The outer loop increments to
Why this matters: This efficiency is key. We found our answer without needing to inspect every single piece of data. The moment we can give a definitive "yes," we do. We only give a definitive "no" after exhausting all possibilities.
Try it yourself
Time to put your knowledge to the test.
- 1Shopping Cart SearchYou have an
ArrayListofProductobjects from a customer's shopping cart in an e-commerce app. EachProductobject has methodsgetName()(returns aString) andgetPrice()(returns adouble). Write a methodfindProductByName(ArrayList<Product> cart, String name)that takes the cart and a product name, and returns theProductobject if it's found. If no product with that name is in the cart, it should returnnull. Hint: Your loop will iterate through theArrayList. Inside the loop, you'll get theProductat the current index and then use itsgetName()method to compare with the target name. Remember to use.equals()for comparing Strings! - 2Game Board CheckYou are given an 8x8 2D
chararray representing a game board. An empty square is represented by the character'-'. Write a methodisBoardFull(char[][] board)that returnstrueif there are no empty squares left on the board, andfalseotherwise. Hint: You'll need a nested loop to check every square. What can you do the moment you find the first'-'? Does that give you the final answer right away?
Practice — 8 questions
In simple terms, linear search is about finding an item in a list by checking each one, in order, until you find what you're looking for or you've checked them all.
int[] scores = {1200, 4500, 3250, 5000, 2100};
int targetScore = 5000;
- 4.14.A: Develop code used for linear search algorithms to search for specific information in a collection and determine the results of executing a search.
- 4.14.A.1
- Linear search algorithms are standard algorithms that check each element in order until the desired value is found or all elements in the array or ArrayList have been checked. Linear search algorithms can begin the search process from either end of the array or ArrayList.
- 4.14.A.2
- When applying linear search algorithms to 2D arrays, each row must be accessed then linear search applied to each row of the 2D array.
flowchart TD
A[Start] --> B{Initialize index i = 0};
B --> C{Is i < array.length?};
C -- Yes --> D{Is array[i] == target?};
C -- No --> G[Return -1 (Not Found)];
D -- Yes --> E[Return i (Found)];
D -- No --> F{Increment i};
F --> C;
Read what Saavi narrates
Hello, I'm Saavi, and I'm so glad you're here with me at Shrutam.
Imagine you're scrolling through a giant playlist with hundreds of songs, looking for that one specific track that's stuck in your head. What do you do? You probably start at the top and check each song, one by one... "Nope, not this one... not this one... ah, there it is!"
That simple, methodical process is exactly what we're learning about today. It's a fundamental computer science algorithm called a linear search. We use it to find a target value in a list by looking at each item, one at a time, until we either find it or run out of items.
Let's look at a quick example. Imagine we have an array of integers, maybe they're jersey numbers for a basketball team: ten, thirty, twenty-three, five, and twelve. We want to find the player with jersey number twenty-three.
Our code will start a loop at the very first number, which is ten. Is ten equal to twenty-three? No. So we move on.
The next number is thirty. Is thirty equal to twenty-three? No. Move on.
The next number is twenty-three. Is twenty-three equal to twenty-three? Yes! We found it. We can stop searching and report that we found it at index two. We don't even need to look at the rest of the numbers.
Now, one of the most common mistakes students make is with the "not found" case. It's so tempting to write code that says, "if the first number isn't a match, then the number must not be in the list." But that's not right! That's like looking for your friend at a party, only checking the first person by the door, and then declaring your friend isn't there. You can only be sure your friend isn't there after you've scanned the entire room.
In our code, this means we only return our "not found" signal, which is often the number negative one, *after* our loop has finished completely. If the loop finishes, it means we checked every single jersey and never got a match. Only then can we be sure.
Linear search is a building block for so much of what you'll do in computer science. Practice it, understand its logic, and you'll have a reliable tool you can use anywhere. You've got this.
This stops your search after checking only the first non-matching element. You can only conclude an item is missing after you've checked *every* element.
Place your `return -1;` or `return false;` statement *after* the loop has completely finished.
Array indices go from `0` to `length - 1`. If `arr.length` is 5, the valid indices are 0, 1, 2, 3, 4. Using `<=` would cause the loop to try accessing `arr[5]`, which doesn't exist, leading to an `ArrayIndexOutOfBoundsException`.
Always use `< arr.length` for your loop condition when iterating from the start.
If your method has a return type (like `int` or `boolean`), it *must* return a value in every possible scenario. If the loop finishes without finding the item, the method will cause a compiler error because it might not return anything.
Ensure there's a `return` statement after the loop to handle the case where the target is never found.
Writing `grid[j][i]` instead of `grid[i][j]` (where `i` is the row loop variable and `j` is the column) accesses the grid in a column-major order. While not always an error, it's confusing and goes against convention. It can also cause an `ArrayIndexOutOfBoundsException` if the grid is not a square.
Consistently use the outer loop variable for the first bracket (row) and the inner loop variable for the second bracket (column): `grid[row][col]`.
This mixes array and `ArrayList` syntax. `ArrayList`s are objects and use methods for everything.
Be consistent. For `ArrayList`, it's always `.size()` and `.get(i)`. For arrays, it's `.length` and `[i]`.