Knowledge Guide
HomeConcurrencyConcurrency Problems

Problem 3 Linear Search with Indices and Occurrences

Overview

To enhance the linear search to find and count all occurrences, we'll store each occurrence in a shared collection and count the total number of occurrences in the end. This method will provide both the indices where the target element appears and the total number of appearances in the array. With multithreading, each thread will examine its chunk of the array, reducing the overall time for the search.

Multithreading in Linear Search for Indices and Occurrences

The process is similar to the multithreaded search for all occurrences, but with the addition of counting the total number of occurrences:

  1. Divide the Work: Split the array into smaller segments or "chunks" for each thread.
  2. Concurrent Execution: Threads will search their chunks for the target element.
  3. Collecting Results: Use a shared collection (e.g., a list) to append indices of occurrences. Use a shared variable (e.g., an integer) to store the count of occurrences.
  4. Synchronization: Ensure thread-safe updates to shared data structures using synchronization mechanisms.

Step-by-step Algorithm

  1. Initialize the array (arr) and the target element (key) to search for.

  2. Initialize a shared list (foundIndices) to store the indices of all occurrences.

  3. Initialize a shared variable (occurrencesCount) to store the count of occurrences.

  4. Define locks for synchronizing access to shared resources (indicesLock for foundIndices and countLock for occurrencesCount).

  5. Define a function SearchIndicesOccurrences(threadId, arr, key):

    • Calculate the size of the chunk each thread will work on (chunkSize) based on the number of threads.
    • Calculate the start and end indices for the thread's assigned chunk.
    • Initialize an empty list (localIndices) to store the indices found by this thread.
    • Initialize a variable (localCount) to count the occurrences found by this thread.
    • For each index (i) in the assigned range:
      • If arr[i] is equal to key:
        • Add i to localIndices.
        • Increment localCount.
    • Lock indicesLock:
      • Extend foundIndices with localIndices.
    • Lock countLock:
      • Add localCount to occurrencesCount.
  6. Create an array of threads (threads) with a size of NUM_THREADS.

  7. For each threadId from 0 to NUM_THREADS - 1:

    • Create a new thread that runs the SearchIndicesOccurrences function with threadId, arr, and key as arguments.
    • Store the thread in the threads array.
  8. Start all the created threads (i.e., thread.start()).

  9. For each thread in the threads array:

    • Wait for the thread to complete its execution (i.e., thread.join()).
  10. If foundIndices is empty:

    • Output "Element not found in the array."
  11. If foundIndices is not empty:

    • Output "Element found {occurrencesCount} times at indices: {foundIndices}".
  12. End the program.

Algorithm Walkthrough

Input:

Step 1: We initialize arr and key.

Step 2: We initialize foundIndices = [] and occurrencesCount = 0.

Step 3: Locks indicesLock and countLock are defined but not locked at this point.

Step 5: This is the core function, but we don't execute it yet. We'll come back to it when a thread is started.

Step 6: We create an array threads of size 2 (since NUM_THREADS = 2).

Step 7: We're creating 2 threads here.

For threadId = 0:

For threadId = 1:

Both threads are added to the threads array but not yet started.

Step 8: Start both threads:

For threadId = 0:

For threadId = 1:

Step 9: Wait for both threads to complete.

Step 10: Check if foundIndices is empty. It's not.

Step 11: Output result:

Step 12: End of the program.

This walkthrough assumes that the locks work correctly to avoid any race conditions or conflicts while accessing shared resources from different threads. The main idea here is to split the array into chunks and let each thread work on its chunk independently.

Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
java
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Solution {

  private static final int SIZE = 4000;
  private static final int NUM_THREADS = 4;

  private static final List<Integer> foundIndices = new ArrayList<>(); // Shared list to store the indices of all occurrences
  private static int occurrencesCount = 0; // Shared variable to store the count of occurrences

  private static final Object indicesLock = new Object(); // Lock for synchronizing access to foundIndices
  private static final Object countLock = new Object(); // Lock for synchronizing access to occurrencesCount

  // Function executed by each thread to search for indices and occurrences
  private static void searchIndicesOccurrences(
    int threadId,
    int[] arr,
    int key
  ) {
    int chunkSize = arr.length / NUM_THREADS;
    int start = threadId * chunkSize;
    int end = (threadId == NUM_THREADS - 1) ? arr.length : start + chunkSize;

    List<Integer> localIndices = new ArrayList<>();
    int localCount = 0;

    for (int i = start; i < end; ++i) {
      if (arr[i] == key) {
        localIndices.add(i);
        localCount++;
      }
    }

    if (!localIndices.isEmpty()) {
      synchronized (indicesLock) {
        foundIndices.addAll(localIndices);
      }
    }

    if (localCount > 0) {
      synchronized (countLock) {
        occurrencesCount += localCount;
      }
    }
  }

  public static void main(String[] args) {
    // Create an array and fill it with random numbers between 0 and 99
    int[] arr = new int[SIZE];
    Random random = new Random();
    for (int i = 0; i < SIZE; ++i) {
      arr[i] = random.nextInt(100);
    }

    Thread[] threads = new Thread[NUM_THREADS]; // Array of threads
    int key = 19; // Element to find

    // Start the threads
    for (int i = 0; i < NUM_THREADS; ++i) {
      int threadId = i;
      threads[i] = new Thread(() -> searchIndicesOccurrences(threadId, arr, key)
      );
      threads[i].start();
    }

    // Wait for all threads to complete
    for (Thread thread : threads) {
      try {
        thread.join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    // Output the results
    if (foundIndices.isEmpty()) {
      System.out.println("Element not found in the array.");
    } else {
      System.out.print(
        "Element found " + occurrencesCount + " times at indices: "
      );
      for (int index : foundIndices) {
        System.out.print(index + " ");
      }
      System.out.println();
    }
  }
}
🤖 Don't fully get this? Learn it with Claude

Stuck on Problem 3 Linear Search with Indices and Occurrences? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Problem 3 Linear Search with Indices and Occurrences** (Concurrency). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Problem 3 Linear Search with Indices and Occurrences** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Problem 3 Linear Search with Indices and Occurrences**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Problem 3 Linear Search with Indices and Occurrences**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes