您的位置:首页 > 其它

《Cracking the Coding Interview》——第11章:排序和搜索——题目3

2014-03-21 21:26 453 查看
2014-03-21 20:55

题目:给定一个旋转过的升序排序好的数组,不知道旋转了几位。找出其中是否存在某一个值。

解法1:如果数组的元素都不重复,那么我的解法是先找出旋转的偏移量,然后进行带偏移量的二分搜索。两个过程都是对数级的。

代码:

// 11.3 Given a sorted array rotated by a few positions, find out if a value exists in the array.
// Suppose all elements in the array are unique.
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;

int rotatedBinarySearch(vector<int> &v, int n, int key)
{
int offset;

if ((int)v.size() < n || n <= 0) {
return -1;
}

int ll, rr, mm;

if (v[0] < v[n - 1]) {
offset = 0;
} else {
ll = 0;
rr = n - 1;
while (rr - ll > 1) {
mm = (ll + rr) / 2;
if (v[mm] > v[ll]) {
ll = mm;
} else {
rr = mm;
}
}
offset = rr;
}

ll = 0;
rr = n - 1;
while (ll <= rr) {
mm = (ll + rr) / 2;
if (key < v[(mm + offset) % n]) {
rr = mm - 1;
} else if (key > v[(mm + offset) % n]) {
ll = mm + 1;
} else {
return (mm + offset) % n;
}
}
return -1;
}

int main()
{
int n;
int i;
vector<int> v;

while (scanf("%d", &n) == 1 && n > 0) {
v.resize(n);
for (i = 0; i < n; ++i) {
scanf("%d", &v[i]);
}
scanf("%d", &i);
printf("%d\n", rotatedBinarySearch(v, n, i));
}

return 0;
}


解法2:如果数组的元素可能存在重复,那么我的思路仍然是先二分查找找出偏移量,然后执行带偏移量的二分搜索。不过,在找偏移量的过程中可能会出现无法决定向左还是向右的情况,比如这两个例子{1, 3, 1, 1, 1}{1, 1, 1, 3, 1},在第一次二分时,左中右的元素都是‘1’,无法确定应该往哪边走。这时就得扫描整段,{1, 1, 1}全部是同一元素,{1, 3, 1}存在不同元素,所以应该选择{1, 3, 1}进行二分,因为在首尾相同的情况下,中间如果有不同元素的话,表示旋转的偏移量应该会落在这个区间里。找到偏移量以后,之后的查找就是严格二分的了。

代码:

// 11.3 Given a sorted array rotated by a few positions, find out if a value exists in the array.
// Suppose the array may contain duplicates, what's it gonna be then?
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;

int rotatedBinarySearch(vector<int> &v, int n, int key)
{
int offset;

if ((int)v.size() < n || n <= 0) {
return -1;
}

int ll, rr, mm;
int i;

ll = 0;
rr = n - 1;
while (rr - ll > 1 && v[ll] == v[rr]) {
mm = (ll + rr) / 2;
if (v[mm] > v[ll]) {
ll = mm;
break;
} else if (v[mm] < v[ll]) {
rr = mm;
break;
} else {
for (i = ll; i < mm - 1; ++i) {
if (v[i] != v[i + 1]) {
break;
}
}
if (i < mm - 1) {
rr = mm;
break;
}
for (i = mm; i < rr - 1; ++i) {
if (v[i] != v[i + 1]) {
break;
}
}
if (i < rr - 1) {
break;
}

// if all elements are the same, it ends here
return (v[0] == key) ? 0 : -1;
}
}

if (v[ll] < v[rr]) {
offset = 0;
} else {
// here it is guaranteed v[ll] != v[rr]
while (rr - ll > 1) {
mm = (ll + rr) / 2;
if (v[mm] >= v[ll]) {
ll = mm;
} else {
rr = mm;
}
}
offset = rr;
}

// the binary search part remains the same, difference lies in how we find the 'offset'.
ll = 0;
rr = n - 1;
while (ll <= rr) {
mm = (ll + rr) / 2;
if (key < v[(mm + offset) % n]) {
rr = mm - 1;
} else if (key > v[(mm + offset) % n]) {
ll = mm + 1;
} else {
return (mm + offset) % n;
}
}

return -1;
}

int main()
{
int n;
int i;
vector<int> v;

while (scanf("%d", &n) == 1 && n > 0) {
v.resize(n);
for (i = 0; i < n; ++i) {
scanf("%d", &v[i]);
}
scanf("%d", &i);
printf("%d\n", rotatedBinarySearch(v, n, i));
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐