Searching & SortingProblem 9 of 36

Searching in an array where adjacent differ by at most k

Brute Force
Time: O(n)
Space: O(1)
Optimal
Time: O(n/k)
Space: O(1)

Problem Statement

Given an array where adjacent elements differ by at most k, search for a given element x. If x is present, return its index; otherwise, return -1.

Constraints:

  • Adjacent elements differ by at most k: |arr[i] - arr[i+1]| <= k
  • Array is not necessarily sorted
  • k >= 1

Example:

  • Input: arr = [4, 5, 6, 7, 6], k = 1, x = 6
  • Output: 2 (or 4, since 6 appears at both indices)
  • Explanation: 6 is found at index 2

Example 2:

  • Input: arr = [20, 40, 50, 70, 70, 60], k = 20, x = 60
  • Output: 5
  • Explanation: 60 is found at index 5

Approach 1: Brute Force (Linear Search)

Intuition

Simply scan through all elements to find the target.

Algorithm

  1. Traverse the array from index 0 to n-1
  2. If current element equals x, return index
  3. Return -1 if not found
java
public class Solution {
    public int search(int[] arr, int x) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == x) {
                return i;
            }
        }
        return -1;
    }
}

Complexity Analysis

  • Time Complexity: O(n) - May need to check all elements
  • Space Complexity: O(1) - No extra space

Approach 2: Jump Search Based on Difference (Optimal)

Intuition

Since adjacent elements differ by at most k, we can calculate the minimum number of steps needed to reach x from the current element and jump directly.

Key Insight:

  • If arr[i] = a and we're looking for x
  • Difference = |x - a|
  • Minimum steps to reach x = ceil(|x - a| / k)
  • We can safely skip to index i + max(1, |x - a| / k)

Algorithm

  1. Start from index i = 0
  2. If arr[i] == x, return i
  3. Calculate jump = max(1, |arr[i] - x| / k)
  4. Move i += jump
  5. Repeat until i >= n
  6. Return -1 if not found
java
public class Solution {
    public int searchWithJump(int[] arr, int k, int x) {
        int n = arr.length;
        int i = 0;
        
        while (i < n) {
            // Found the element
            if (arr[i] == x) {
                return i;
            }
            
            // Calculate minimum steps needed
            int diff = Math.abs(arr[i] - x);
            int jump = Math.max(1, diff / k);
            
            i += jump;
        }
        
        return -1;
    }
}

Dry Run Example

arr = [20, 40, 50, 70, 70, 60], k = 20, x = 60 i = 0: arr[0] = 20 != 60 diff = |20 - 60| = 40 jump = max(1, 40/20) = 2 i = 0 + 2 = 2 i = 2: arr[2] = 50 != 60 diff = |50 - 60| = 10 jump = max(1, 10/20) = max(1, 0) = 1 i = 2 + 1 = 3 i = 3: arr[3] = 70 != 60 diff = |70 - 60| = 10 jump = max(1, 10/20) = max(1, 0) = 1 i = 3 + 1 = 4 i = 4: arr[4] = 70 != 60 diff = |70 - 60| = 10 jump = max(1, 10/20) = max(1, 0) = 1 i = 4 + 1 = 5 i = 5: arr[5] = 60 == 60 FOUND! Return 5

Why This Works

arr = [4, 5, 6, 7, 6], k = 1 Looking for x = 6, starting at i = 0, arr[0] = 4 Since adjacent elements differ by at most 1: - To go from 4 to 6, we need at least |6-4|/1 = 2 steps - So we can safely jump 2 positions arr[0]=4 → arr[1] can be 3,4,5 (at most k=1 away) → arr[2] can be 2,3,4,5,6 (at most 2k away from arr[0]) If x=6 exists and arr[0]=4, it cannot be at index 1 It CAN be at index 2 or beyond

Complexity Analysis

  • Time Complexity: O(n/k) average case
    • In the worst case (x is at the end, values oscillate), it's O(n)
    • In the best case, we jump in large steps
  • Space Complexity: O(1) - Only using variables

Finding All Occurrences


Variation: Bidirectional Search

Start from both ends and meet in the middle.


Edge Cases


Comparison with Standard Approaches

| Approach | Time Complexity | When to Use | |----------|----------------|-------------| | Linear Search | O(n) | Always works | | Jump Search | O(n/k) avg | Adjacent differ by ≤ k | | Binary Search | O(log n) | Sorted array | | Hash Table | O(1) avg | Preprocessing allowed |


Key Takeaways

  1. Constraint Exploitation: The constraint |arr[i] - arr[i+1]| <= k allows smart jumping
  2. Jump Calculation: jump = max(1, |current - target| / k) is the key formula
  3. Safe Skipping: We can safely skip positions because target can't exist there
  4. Average Case: O(n/k) is much better than O(n) when k is small
  5. Worst Case: Still O(n) when values oscillate around target
  6. Applications: Step-limited search, constrained sequences, sensor data with limited change rate