《程序员面试金典(第6版)》面试题 10.05. 稀疏数组搜索(二分法,分治算法入门题目,C++)

题目描述

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

示例1:

  • 输入: words = [“at”, “”, “”, “”, “ball”, “”, “”, “car”, “”, “”,“dad”, “”, “”], s = “ta”
  • 输出:-1
  • 说明: 不存在返回-1。

示例2:

  • 输入:words = [“at”, “”, “”, “”, “ball”, “”, “”, “car”, “”, “”,“dad”, “”, “”], s = “ball”
  • 输出:4

提示:

  • words的长度在[1, 1000000]之间

解题思路与代码

  • 这道题是一道十足的简单题,我们可以用两种方式去解决它。一种方法是顺序查找元素,那么它的时间复杂度为O(n),另一种就是使用二分法,它的时间复杂度为O(log(n)),n为字符数组中元素的个数。下面就让我们来看看这两种方法各自的实现是什么?

方法一: 顺序查找

很简单,就是一个for循环去比较元素,如果相等,返回下标,如果找不到目标元素,返回 -1。

具体的代码如下:

class Solution {
public:
    int findString(vector<string>& words, string s) {
        for(int i = 0; i < words.size(); ++i){
            if(words[i] == s) return i;
        }
        return -1;
    }
};

在这里插入图片描述

复杂度分析

时间复杂度 O(n)
空间复杂度 O(1)

方法二:二分查找

  • 我们首先设置两个指针left 与 right,分别指向数组的首元素与尾元素。然后使用while循环去遍历。
  • 我们找出数组的中间元素mid,用一个temp遍历去记录此时mid的值。如果mid为空,就while循环遍历mid。++mid。mid < right 是内层for循环的停止条件。这个目的是使中间元素的字符串不为空。
  • 假如最后mid 还是为空,我们就缩小right的范围,使right = temp -1;然后跳过此次循环。
  • 之后,我们开始进行二分查找与比较操作。这里我们要用到string自带的成员比较函数compare
    • 如果word[mid] = s,就直接返回mid。
    • 如果word[mid] < s,left = mid + 1;
    • 否则right = mid -1;

具体的实现请看代码

class Solution {
public:
    int findString(vector<string>& words, string s) {
        int left = 0;
        int right = words.size() - 1;
        while(left <= right){
            int mid = (left + right) / 2;
            int temp = mid;
            while(words[mid] == "" && mid < right)
                ++mid;
            if(words[mid] == ""){
                right = temp -1;
                continue;
            }
            int cmp = words[mid].compare(s);
            if(cmp == 0) return mid;
            else if(cmp < 0) left = mid + 1;
            else right = mid - 1;
        }
        return -1;
    }
};

在这里插入图片描述

复杂度分析

首先,我们来分析这段代码的时间复杂度。

  • 在最好的情况下,如果目标字符串是中间的元素,时间复杂度为 O(1)。但这不是我们关心的情况,我们需要分析最坏情况和平均情况。

  • 在最坏情况下,空字符串的数量可能非常多,导致代码的时间复杂度降低。每次执行循环时,我们可能需要跳过 k 个空字符串,其中 k 是当前区间内的空字符串数量。在最坏情况下,k 可能接近 n/2,这将使时间复杂度变为 O(k * log(n)),即 O(n * log(n))。

  • 然而,在平均情况下,空字符串应该较少,时间复杂度应接近 O(log(n))。这是因为二分查找法在平均情况下具有 O(log(n)) 的时间复杂度,而跳过空字符串只会稍微影响性能。

接下来,我们分析空间复杂度。

  • 这段代码中,我们只使用了一些辅助变量(如 left、right、mid、temp 和 cmp),而没有使用任何额外的数据结构。因此,空间复杂度为 O(1)。这意味着代码具有很好的空间效率。

总结一下,这段代码在平均情况下的时间复杂度为 O(log(n)),空间复杂度为 O(1)。在最坏情况下,时间复杂度可能会降低,但这取决于空字符串的分布情况。

总结

  • 这道题其实可以算是学习二分法或者分治思想的入门题目,还是很有必要去学习和掌握一下的。
  • 觉得我写的还行的小伙伴们请给我点一个赞,你们的赞就是对我持续输出优质内容的最大鼓励,谢谢!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿宋同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值