大厂高频经典面试题(64)-稀疏数组搜索

1. 题目:

有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置。

示例:
输入:在字符串数组{“at”, “”, “”, “”, “ball”, “”, “”, “car”, “”, “”, “dad”, “”, “”}中查找“ball”
输出:4

2. 解题思路:

需要在包含空字符串的有序字符串数组中,查找目标字符串的位置。由于数组中散布着空字符串,我们需要对标准二分查找进行修改,以便可以正确处理这些空字符串。

解决方案思路

1)跳过空字符串:在二分查找过程中,遇到空字符串时需要调整指针位置

2)比较字符串:使用标准字符串比较来确定搜索方向

3)处理边界条件:确保算法在全是空字符串或目标不存在时能正确工作

3. 图解流程:

使用多张图,演示下面代码的整个流程:

图1:初始数组状态

索引: 0    1   2   3    4      5   6    7     8   9   10     11  12
值: ["at", "", "", "", "ball", "", "", "car", "", "", "dad", "", ""]
查找目标: "ball"

图2:第一次循环

left=0, right=12
跳过左侧空字符串: left保持0("at")
跳过右侧空字符串: right保持12("")
mid=6 → arr[6]="" → 向右移动mid到7("car")
比较:"car" > "ball" → right=mid-1=6

图3:第二次循环

left=0, right=6
跳过左侧空字符串: left保持0("at")
跳过右侧空字符串: right保持6("")
mid=3 → arr[3]="" → 向右移动mid到4("ball")
比较:"ball" == "ball" → 返回4

图4:查找"apple"的流程

left=0, right=12
mid=6 → "car" > "apple" → right=5
mid=2 → "" → 向右移动mid=4("ball")
"ball" > "apple" → right=3
mid=1 → "" → 向右移动mid=0("at")
"at" < "apple" → left=1
left(1) > right(0) → 返回-1

图5:查找"dad"的流程

left=0, right=12
mid=6 → "car" < "dad" → left=7
mid=9 → "" → 向右移动mid=10("dad")
"dad" == "dad" → 返回10

这个算法的关键流程可以总结为:

  • 跳过两端的空字符串
  • 计算中间位置
  • 如果中间是空字符串,则向右或向左找到第一个非空字符串
  • 进行标准二分比较
  • 根据比较结果调整左右边界

整个过程通过跳过空字符串和调整搜索范围,保证了在稀疏数组中的高效查找。

4. 代码完整实现(C++):

#include <iostream>
#include <string>
#include <vector>

// 在稀疏字符串数组中查找目标字符串
int sparseSearch(const std::vector<std::string>& arr,
                 const std::string& target) {
    int left = 0;
    int right = arr.size() - 1;

    while (left <= right) {
        // 跳过左侧的空字符串
        while (left <= right && arr[left] == "") {
            left++;
        }
        // 跳过右侧的空字符串
        while (left <= right && arr[right] == "") {
            right--;
        }

        // 如果所有元素都是空字符串
        if (left > right) {
            return -1;
        }

        int mid = left + (right - left) / 2;

        // 如果中间是空字符串,向右移动直到找到非空字符串
        while (mid <= right && arr[mid] == "") {
            mid++;
        }

        // 如果右边全是空字符串,向左移动
        if (mid > right) {
            mid = left + (right - left) / 2;
            while (mid >= left && arr[mid] == "") {
                mid--;
            }
            // 如果左边也全是空字符串
            if (mid < left) {
                return -1;
            }
        }

        // 标准二分查找比较
        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }

    return -1;
}

// 测试函数
int main() {
    std::vector<std::string> arr = {"at",  "", "", "",    "ball", "", "",
                                    "car", "", "", "dad", "",     ""};

    // 测试用例1:查找存在的字符串
    std::string target1 = "ball";
    int result1 = sparseSearch(arr, target1);
    std::cout << "查找 \"" << target1 << "\" 的结果: " << result1 << std::endl;

    // 测试用例2:查找不存在的字符串
    std::string target2 = "apple";
    int result2 = sparseSearch(arr, target2);
    std::cout << "查找 \"" << target2 << "\" 的结果: " << result2 << std::endl;

    // 测试用例3:查找另一个存在的字符串
    std::string target3 = "dad";
    int result3 = sparseSearch(arr, target3);
    std::cout << "查找 \"" << target3 << "\" 的结果: " << result3 << std::endl;

    return 0;
}

5. 代码分析:

算法分析

1)时间复杂度:平均O(log n),最坏O(n)(当数组中大部分是空字符串时)
2)空间复杂度:O(1),只使用了常数级别的额外空间
3)关键点说明:

  • 在每次迭代中跳过左右两侧的空字符串
  • 处理中间元素为空字符串的情况
  • 确保在全是空字符串时能正确返回-1
  • 使用标准字符串比较来确定搜索方向

测试用例说明

1)测试用例1:查找存在的字符串"ball",预期输出4
2)测试用例2:查找不存在的字符串"apple",预期输出-1
3)测试用例3:查找另一个存在的字符串"dad",预期输出10

这个实现能够正确处理稀疏字符串数组中的搜索问题,即使在数组中有大量空字符串的情况下也能工作。

5. 运行结果:

查找 "ball" 的结果: 4
查找 "apple" 的结果: -1
查找 "dad" 的结果: 10

感谢您的阅读。原创不易,如您觉得有价值,请点赞,关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水草

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值