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
感谢您的阅读。原创不易,如您觉得有价值,请点赞,关注。