数据结构与算法篇-线性查找-获取目标元素位置信息

线性查找 -- 获取目标元素位置

问题描述

输入:数组 arr= [10, 25, 7, 42, 18],目标元素 target=42

输出:如果目标元素存在,则返回目标元素在数组中的索引位置;否则,返回 -1。

示例1:

  • 数组 arr= [10, 25, 7, 42, 18],目标元素 target=42
  • 输出:3

示例2:

  • 数组 arr= [10, 25, 7, 42, 18],目标元素 target=50
  • 输出:-1

状态定义

findRecursive(arr, target, i) 表示:

  • 如果目标元素存在,则它必存在于数组的前i个元素中,且目标元素在数组中的索引位置为 i-1
  • 否则,表示目标元素不存在,值为 -1。

基准情况:

findRecursive(arr, target, 0) 表示数组arr中没有要考虑的元素了,即要查找的数组为空,显然值为-1。

推导递推关系

要计算 findRecursive(arr, target, i), 让我们考虑数组arr 的 第i个元素,即arr[i-1]

有两种情况:

情况 1:arr[i-1] 等于 target ,就返回 i-1

情况 2:arr[i-1] 不等于 target,则需要计算目标元素target在数组arr的前i-1个元素中的索引。

请总结下递推关系:

txt 复制代码
findRecursive(arr, target, i) =
    if arr[i-1] == target
        then i-1
     else findRecursive(arr, target, i-1)

朴素递归解

java 复制代码
public static int findRecursive(int[] arr, int target){
    return findRecursiveHelper(arr, target, arr.length);
}

private static int findRecursiveHelper(int[] arr, int target, int i) {
    if (i == 0) {
        return -1;
    }

    if (arr[i-1] == target) {
        return i-1;
    }
    return findRecursiveHelper(arr, target, i-1);
}

迭代解

java 复制代码
public static int findIterative(int[] arr, int target){
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == target) {
            return i;
        }
    }
    return -1;
}

优化 1:存在热点数据

当数据存在非均匀访问模式(某些元素的被访问频率高于其它元素)时,可以对数组使用 "交换相邻元素法"。

java 复制代码
public static int findIterative(int[] arr, int target){
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == target) {
            if (i > 0) {
                // "交换相邻元素法"
                int temp = arr[i];
                arr[i] = arr[i-1];
                arr[i-1] = temp;
            }
            return i;
        }
    }
    return -1;
}

优化 2:有序性

假设数组是有序的,依然使用线性查找。那么,可以进行提前终止优化。

对从右向左的递归方向来说,如果数组元素比目标元素小,那么就可以说明目标元素不存在。

解释:

情况 3:arr[i-1] < target,说明数组的前 i 个元素都小于 target,即表示不用再递归到前i-1个元素中去查找了,直接可判断目标元素不存在,返回-1

示例代码

java 复制代码
private static int findRecursiveHelper(int[] arr, int target, int i) {
    if (i == 0) {
        return -1;
    }

    if (arr[i-1] == target) {
        return i-1;
    }
		// 优化:针对有序数组
    if (arr[i-1] < target) {
        return -1;
    }

    return findRecursiveHelper(arr, target, i-1);
}

对从左向右的迭代方向来说,如果数组元素比目标元素大,那么就可以说明目标元素不存在。

解释:

对从左向右的迭代方向来说,若 arr[i] > target,由于数组有序且 arr[i] 是尚未检查区间 [i, n-1] 中的最小元素,它已经大于 target,因此 target 不可能出现在后续任何位置,可以直接判断不存在,返回-1

示例代码

java 复制代码
 public static int findIterative(int[] arr, int target){
     for (int i = 0; i < arr.length; i++) {
         if (arr[i] == target) {
             if (i > 0) {
                 // 优化:"交换相邻元素法"。
                 int temp = arr[i];
                 arr[i] = arr[i-1];
                 arr[i-1] = temp;
             }
             return i;
         }
         // 优化:针对有序数组
         if(arr[i] > target) {
             return -1;
         }
     }
     return -1;
 }

注意:

  • 实际工程中,这两种优化通常不会同时使用,因为前者会破坏数组的有序性。
相关推荐
YouEmbedded3 个月前
解码查找算法与哈希表
数据结构·算法·二分查找·散列表·散列查找·线性查找
简 洁 冬冬2 年前
001 线性查找
lua·线性查找