前面做了下线性表有关的操作,主要是去除线性表中的重复值,(数组和链表),这一篇做两道在线性表中查找的题目。
LeetCode线性表的操作(Remove Duplicates)
1.Search in Rotated Sorted Array
原文链接:点击这里进入
基本内容:
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
解题思想:
这题目最一开始想到的肯定是从头开始一个一个的扫描,但是时间复杂度为O(n),这种题目在面试如果采取这样做的话是肯定拿不到offer的。因为是两个部分有序的。全部有序的情况下我们是可以采用二分查找法来做的。这个数组实际上是排序数组的变异品种。
解法一:因为我们在排序好的数组中可以采用二分查找的方法,这个数组其实是两个排序好的数组,我们可以首先找到一个下标值,把这个数组分成两个排序好的数组,然后根据传进来的值去 单个排序好的数组中进行二分查找。这个特定下标前面是一个排序好的数组,后面是一个排序好的数组且这个数组的元素中的任何一个值都比前面的数组中的值小。
需要考虑下列4种不同的情况:
- 5,1,2,3,4 (前面的数组只有一个值)
- 5,6,7,8,1 (后面的数组只有一个值)
- 5,6,1,2,3 (最正常的情况)
- 1,2,3,4,5 (已经排序好的情况,也就是未发生旋转,这个需要特殊表示,判断情况是第一个值是否小于最后一个值)
查找特定下标的函数:
int findSpecialPosition( int a[ ], int n )
{
int begin = 0;
int end = n - 1;
int half = ( begin + end ) >> 1;
//get the pivot
if( a[ begin ] < a[ end ] )//sorted
return end;
while( half + 1 <= end && a[ half ] < a[ half + 1] && begin <= end )
{
if( a[ half ] >= a[ begin ] )
{
begin = half + 1;
}
else
end = half - 1;
half = ( begin + end ) >> 1;
}
return half;
}
把4种特殊的情况都测试一遍就可以通过了,下面根据half 返回的值,可以把原数组分为2个排序好的数组,在排序好的数组中进行二分查找法。
合并代码:
int SearchBinary( int A[], int begin, int end, int target )
{
if( begin <= end )
{
int half = ( begin + end ) >> 1;
while( A[ half ] != target && begin <= end )
{
if( A[ half ] > target )
end = half - 1;
else
begin = half + 1;
half = ( begin + end ) >> 1;
}
if( A[ half ] == target )
return half;
else
return -1;
}
else
return -1;
}
int search(int A[], int n, int target) {
int begin = 0;
int end = n - 1;
int half = ( begin + end ) >> 1;
if( A[ begin ] < A[ end ] )//sorted
SearchBinary( A,0 ,n - 1, target );
while( half + 1 <= end && A[ half ] < A[ half + 1] && begin <= end )
{
if( A[ half ] >= A[ begin ] )
{
begin = half + 1;
}
else
end = half - 1;
half = ( begin + end ) >> 1;
}
begin = 0;
end = n - 1;
if( half + 1 <= end &&A[ half + 1 ] <= target && target <= A[ end ] )
return SearchBinary( A, half + 1, end, target );
else
return SearchBinary( A, begin, half , target );
}//时间复杂度为o(n),空间复杂度o(1)
解法2:可以把这两步合并起来一起做,将二分查找法利用起来,主要是确定左右边界,根据中间的值确定下一步的查找范围。
int search(int A[], int n, int target) {
int first = 0;
int end = n - 1;
int half = ( first + end ) >> 1;
while( first <= end )
{
if( target == A[ half ])
return half;
if( A[ half ] >= A[ first ] )//在数组前面部分,
{
if( A[ half ] >= target && A[ first ] <= target )
end = half;
else
first = half + 1;
}
else
{
if( A[ half ] <= target && target <= A[ end ] )
first = half;
else
end = half - 1;
}
half = ( first + end ) >> 1;
}
return -1;
}
进阶题目:加一个限制条件
2.Search in Rotated Sorted Array II
原文链接:点击这里进入
基本内容:
Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.
解题思想:
这里加了一个可以重复,那么会对原先的数组造成什么影响呢? 会造成后面一个数组中可能有数字与前面一个数组中的数相同,也就是说不再是完全排序的了。(后面数组一定比前面的所有值小),获取到a[half]后需要分3种情况来分别看。
- a[half] > a[first] (这说明还是在划分好的前面的那个数组内部)
- a[half] < a[first] (这说明在划分好的后面的那个数组内部)
- a[half] == a[first] (这种情况不好说,也可以在前面那个数组,也可以在后面那个数组)
对于前2种情况,我们和上边的解法一样就可以了,对于后一种相等的情况,我们也不需要进行特殊的处理,直接让first++就可以了,继续往下判断。
OK,代码:
bool search(int A[], int n, int target) {
int first = 0;
int end = n - 1;
int half = ( first + end ) >> 1;
while( first <= end )
{
if( target == A[ half ])
return true;
if( A[ half ] > A[ first ] )//在数组前面部分,这个部分是不变的
{
if( A[ half ] >= target && A[ first ] <= target )
end = half;
else
first = half + 1;
}
else if( A[ half ] < A[ first ])
{
if( A[ half ] <= target && target <= A[ end ] )
first = half;
else
end = half - 1;
}
else
first++;
half = ( first + end ) >> 1;
}
return false;
}
二分查找法的有关题目暂时就写这么多了,如有发现继续添加。