本文共 2046 字,大约阅读时间需要 6 分钟。
在之前的讨论中,我们探讨了如何在旋转排序数组中搜索特定目标元素的问题。然而,该问题的升级版本引入了一个新的要素:允许数组中存在重复元素。这是否会影响算法的运行时间复杂度?我们需要深入分析这一点。
假设有一个原本是按升序排列的数组,随机旋转了一个未知的位置。例如,原数组 0 1 2 4 5 6 7
可能会变成 4 5 6 7 0 1 2
。现在,我们需要编写一个函数,判断给定的目标值是否存在于该数组中。需要注意的是,数组中可能包含重复的元素。
在传统的旋转排序数组搜索问题中,我们可以利用二分查找的思想,通过比较数组的中间值与目标值来缩小搜索范围。然而,当数组中存在重复元素时,传统的二分查找逻辑可能会遇到问题。例如,当 low
、mid
和 high
都指向相同的值时,如何确定下一步操作?这时,简单的二分查找可能会陷入死循环。
为了应对重复元素的情况,我们可以对传统的二分查找逻辑进行修改。当 nums[low]
、nums[mid]
和 nums[high]
中的值相等时,我们需要采取额外的逻辑来跳出这种情况,以避免无限循环。具体来说,当 nums[mid]
等于目标值时,我们可以直接返回 true
。如果 nums[mid]
等于 nums[low]
,则我们可以将 low
逐步递增,直到找到一个不同的值。同理,如果 nums[mid]
等于 nums[high]
,则将 high
逐步递减。
在传统的二分查找中,时间复杂度为 O(log n)
。在允许重复元素的情况下,虽然逻辑稍微复杂,但时间复杂度仍然保持为 O(log n)
。这是因为,我们只是在某些情况下增加了一个额外的判断步骤,而不会影响算法的整体性能。
public boolean search(int[] nums, int target) { if (nums == null) { return false; } int low = 0; int len = nums.length; int high = len - 1; while (low <= high) { int mid = low + (high - low) / 2; if (nums[mid] == target) { return true; } // 判断当前mid的值与low和high的值的关系 if (nums[low] < nums[mid] || nums[mid] > nums[high]) { // 目标在low和mid之间 if (target < nums[mid] && target >= nums[low]) { high = mid - 1; } else { low = mid + 1; } } else if (nums[mid] < nums[high] || nums[low] < nums[mid]) { // 目标在mid和high之间 if (target <= nums[high] && target > nums[mid]) { low = mid + 1; } else { high = mid - 1; } } else { // 当前mid的值与low和high相同时,尝试移动low或high low++; high--; } } return false;}
让我们通过一些测试案例来验证算法的正确性。
数组:4 5 6 7 0 1 2
目标:0
运行结果:true
数组:4 5 6 7 0 1 2
目标:3
运行结果:false
数组:1 1 1 1
目标:1
运行结果:true
数组:1 1 1 1
目标:2
运行结果:false
允许重复元素的旋转排序数组搜索问题,虽然增加了一定的逻辑复杂性,但对算法的时间复杂度并没有产生影响。通过合理的逻辑修改,我们可以继续使用二分查找的方法,保持 O(log n)
的时间复杂度。
转载地址:http://hpwvz.baihongyu.com/