在有序但是含有空的数组中查找字符串

在有序但是含有空的数组中查找字符串

题目描述:

给定一个字符串数组strs[],在strs中有些位置为null,但在不为null的位置上,其字符串是按照字典序由小到大出现的。在给定一个字符串str,请返回str在strs中出现的最左位置,如果strs中不存在str请输出“-1”。

输入描述:

输出包含多行,第一行包含一个整数n代表strs的长度,第二行一个字符串,代表str,接下来n行,每行包含一个字符串构成,字符串只包含小写字符,如果这一行为“0”,代表该行字符串为空,这n行字符串代表strs。(数据保证当字符串不为空时,所有字符均为小写字母;保证所有的字符串长度都小于10, 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105

输出描述:

输出一个整数,代表要返回的值。

示例1
输入
8 
a
0
a
0
a
ab
ac
0
b
输出
1
说明
在strs中,最左边的“a”在位置1,strs为[null,"a",null,"a","ab","ac",null,"b"]
示例2
输入
4
grep
awk
grep
0
sed
输出
1
说明
strs为["awk","grep",null,"sed"],grep在位置1
备注:

时间复杂度 O ( l o g 2 n ) O(log _{2}n) O(log2n),额外空间复杂度 O ( 1 ) O(1) O(1)


题解:

解法一:

因为题目是先输入待查找字符串,在输入字符串数组,于是可直接在输入时查询,时间复杂度 O ( n ) O(n) O(n)

解法二:

二分,此题与普通的二分区别是:

  • 有重复元素;
  • 存在 null ;

对于重复元素情况:可以在查找到目标元素时继续往左查找,直到查找到最左边的该元素。

对于 null 情况:首先往左遍历,跳过连续的 null ,若左边都是 null 或者 第一个非空的元素小于 target ,则在右边查找,否则继续在非空元素左边查找。

解法二代码:
#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main(void) {
    
    
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    int n;
    string trg;
    cin >> n;
    cin >> trg;
    vector<string> v(n);
    for (int i = 0; i < n; ++i) cin >> v[i];
    
    int l = 0, r = n - 1;
    int ret = -1;
    while (l <= r) {
    
    
        int m = l + r >> 1;
        if (v[m] != "0") {
    
    
            if (v[m] < trg) l = m + 1;
            else {
    
    
                r = m - 1;
                if (v[m] == trg) ret = m;
            }
        } else {
    
    
            int i = m;
            while (i >= l && v[i] == "0") --i;
            if (i < l || v[i] < trg) l = m + 1;
            else {
    
    
                if (v[i] == trg) ret = i;
                r = i - 1;
            }
        }
    }
    cout << ret << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/MIC10086/article/details/108795932