数据结构与算法篇-线性查找-存在性问题

线性查找 -- 存在性问题

问题描述

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

输出:true 还是 false

示例1:

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

示例2:

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

状态定义

hasRecursive(arr, target, i) 表示目标元素target是否在数组arr的前i个元素中。

基准情况:

hasRecursive(arr, target, 0) 表示目标元素target是否在数组arr的前 0 个元素中,即数组arr中没有要考虑的元素了,即要查找的数组为空,显然返回false

推导递推关系

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

有两种情况:

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

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

请总结下递推关系:

txt 复制代码
hasRecursive(arr, target, i) = (arr[i-1] == target) or hasRecursive(arr, target, i-1)

朴素递归解

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

private static boolean hasRecursiveHelper(int[] arr, int target, int i) {
    if (i == 0) {
        return false;
    }

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

迭代解

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

优化 1:存在热点数据

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

java 复制代码
public static boolean hasIterative(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 true;
        }
    }
    return false;
}

优化 2:有序性

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

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

解释:

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

示例代码

java 复制代码
private static boolean hasRecursiveHelper(int[] arr, int target, int i) {
    if (i == 0) {
        return false;
    }

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

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

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

解释:

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

示例代码

java 复制代码
 public static boolean hasIterative(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 true;
         }
         // 优化:针对有序数组
         if(arr[i] > target) {
             return false;
         }
     }
     return false;
 }

注意:

  • 实际工程中,这两种优化通常不会同时使用,因为前者会破坏数组的有序性。
相关推荐
haoly198912 小时前
数据结构与算法篇-线性查找-获取目标元素位置信息
线性查找·递归分析思路
YouEmbedded3 个月前
解码查找算法与哈希表
数据结构·算法·二分查找·散列表·散列查找·线性查找
代码AC不AC9 个月前
【数据结构】二叉树
数据结构·二叉树·学习分享·递归分析·二叉树遍历方法
简 洁 冬冬2 年前
001 线性查找
lua·线性查找