前言 - 引言

题目:
一类有序数组旋转查值问题.
例如:
  有序数组 [ , , , , , , , , ] 旋转后为 [ , , , , , , , , ]
如何从中找出一个值索引, not found return -.

(同事面试时手写最简单一题, 回来和我说了一下, 就记下做个终结者系列)

这种旋转数组有个特点. 大家看图

相信大家豁然开朗了.  这里给个网上烂大街答案

//
// [1, 2, 3, 5, 5, 7, 7, 8, 9]
// 升序数组翻转后
// [5, 7, 7, 8, 9, 1, 2, 3, 5]
// 查找 value, return index, not found return -1;
//
int
search(int a[], int len, int v) {
int begin, end, mid;
// 异常判断
if (a == NULL || len <= )
return -; begin = ;
end = len;
while (begin < end) {
mid = (begin + end) / ;
if (a[mid] == v)
return mid; if (a[begin] < a[mid]) {
// 左边有序 [begin, mid]
if (a[begin] <= v && v < a[mid])
end = mid;
else
begin = mid + ;
} else if (a[begin] > a[mid]) {
// 右边有序 [mid, end)
if (a[mid] < v && v <= a[end - ])
begin = mid + ;
else
end = mid;
} else {
++begin;
}
} // 没有找到
return -;
}

这里使用 [begin, end) 二分法技巧. 代码支持升序旋转重复数组. 最坏情况(全重复)算法复杂度是 O(n).

不过有个问题, 如果不知道是升序 asc 还是降序 desc. 那就需要额外判断了.

// search_sort_state - 排序状态 -1 faild, 0 desc, 1 asc
static int search_sort_state(int a[], int len) {
int state, i, s[];
if (a == NULL || len <= )
return -;
// 默认 desc 降序
if (len == )
return ;
// 1, 2 asc 升序, 但必须反转为 2, 1 变成降序. 因而当前降序 desc 原本就是升序 asc
if (len == )
return a[] > a[]; // 摘取不重复的3个内容
s[] = a[]; // 开始找 s[1]
for (i = ; i < len; ++i) {
if (a[i] == s[])
continue;
break;
}
// 所有值都一样, 走默认降序
if (i >= len)
return ; s[] = a[i];
// 开始找 s[2]
while (i < len) {
if (a[i] == s[] || a[i] == s[]) {
++i;
continue;
}
break;
}
// 只有两个不一样的值, 走默认降序
if (i >= len)
return s[] > s[]; s[] = a[i]; state = ;
state += s[] > s[] ? : -;
state += s[] > s[] ? : -;
state += s[] > s[] ? : -;
return state >= ? : ;
}

最后是自己想得一个排序状态判别的算法(自我感觉巧妙). 试图找出不重复三个数. 例如

6    7    5  有

6 < 7   <

7 > 5   >

5 < 5   <

原生组合是 5   6   7

因而 < 居多是升序. > 居多是降序. (核心原因是旋转数组大小关系只改变一次)

正文 - 扩展

  有了上面铺垫那我们开始码一个问题终结者代码. 希望有所感悟

// bsearch_asc - 二分查找升序查找
static int bsearch_asc(int a[], int begin, int end, int v) {
// 简单判断
if (begin >= end || v < a[begin] || v > a[end - ])
return -; // 二分查找
do {
int mid = (begin + end) / ;
int val = a[mid]; if (val == v)
return mid; if (val < v)
begin = mid + ;
else
end = mid;
} while (begin < end); return -;
} static int search_asc(int a[], int len, int v) {
int begin = , end = len;
// 异常判断
if (begin >= end)
return -; while (begin < end) {
int mid = (begin + end) / ;
if (a[mid] == v)
return mid; if (a[begin] < a[mid]) {
// 左边有序 [begin, mid]
if (a[begin] <= v && v < a[mid])
return bsearch_asc(a, begin, mid, v);
// 右边无序, 继续循环
begin = mid + ;
} else if (a[begin] > a[mid]) {
// 右边有序 [mid, end)
if (a[mid] < v && v <= a[end - ])
return bsearch_asc(a, mid + , end, v);
// 左边无须, 继续循环
end = mid;
} else {
++begin;
}
} // 没有找到
return -;
} // bsearch_desc - 二分查找降序查找
static int bsearch_desc(int a[], int begin, int end, int v) {
// 简单判断
if (begin >= end || v > a[begin] || v < a[end - ])
return -; // 二分查找
do {
int mid = (begin + end) / ;
int val = a[mid]; if (val == v)
return mid; if (val > v)
begin = mid + ;
else
end = mid;
} while (begin < end); return -;
} static int search_desc(int a[], int len, int v) {
int begin = , end = len; while (begin < end) {
int mid = (begin + end) / ;
if (a[mid] == v)
return mid; if (a[begin] > a[mid]) {
// 左边有序 [begin, mid]
if (a[begin] >= v && v > a[mid])
return bsearch_desc(a, begin, mid, v);
// 右边无序, 继续循环
begin = mid + ;
} else if (a[begin] < a[mid]) {
// 右边有序 [mid, end)
if (a[mid] > v && v >= a[end - ])
return bsearch_desc(a, mid + , end, v);
// 左边无须, 继续循环
end = mid;
} else {
++begin;
}
} // 没有找到
return -;
}
//
// 题目:
// 一类有序数组旋转查值问题.
// 例如:
// 有序数组 [ 1, 2, 3, 5, 5, 7, 7, 8, 9 ] 旋转后为 [ 5, 7, 7, 8, 9, 1, 2, 3, 5 ]
// 如何从中找出一个值索引, not found return -1.
int
search_upgrade(int a[], int len, int v) {
int state, i, s[];
if (a == NULL || len <= )
return -;
// 默认 desc 降序
if (len == ) {
if (a[] == v)
return ;
return -;
} if (len == ) {
if (a[] == v)
return ;
if (a[] == v)
return ;
return -;
} // 摘取不重复的3个内容
s[] = a[]; // 开始找 s[1]
for (i = ; i < len; ++i) {
if (a[i] == s[])
continue;
break;
}
// 所有值都一样, 走默认降序
if (i >= len) {
if (s[] == v)
return ;
return -;
} s[] = a[state = i];
// 开始找 s[2]
while (i < len) {
if (a[i] == s[] || a[i] == s[]) {
++i;
continue;
}
break;
}
// 只有两个不一样的值, 走默认降序
if (i >= len) {
if (s[] == v)
return ;
if (s[] == v)
return state;
return -;
} s[] = a[i];
state = ;
state += s[] > s[] ? : -;
state += s[] > s[] ? : -;
state += s[] > s[] ? : -; // desc 降序, 旋转
if (state >= )
return search_desc(a, len, v);
// asc 升序, 旋转
return search_asc(a, len, v);
}

不同分支不同代码, 针对性强. 代码最坏的情况是 O(n).

这里不妨来个测试演示

#include <stdio.h>
#include <stdlib.h> #define LEN(a) (sizeof(a)/sizeof(*a)) // print - 数据内容打印
#define INT_BR (15)
static void print(int a[], int len) {
int i = ;
while (i < len) {
printf(" %d", a[i]);
if (!(++i % INT_BR))
putchar('\n');
}
if (i % INT_BR)
putchar('\n');
} int search_upgrade(int a[], int len, int v); // sort - 旋转查找
int main(int argc, char * argv[]) {
int i, v;
int a[] = { , , , , , , , , };
print(a, LEN(a));
// 开始测试
v = ;
i = search_upgrade(a, LEN(a), v);
printf("%d -> %d\n", v, i);
v = ;
i = search_upgrade(a, LEN(a), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(a, LEN(a), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(a, LEN(a), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(a, LEN(a), v);
printf("%d -> %d\n", v, i); int b[] = { , , , , , , , , , , , , };
print(b, LEN(b));
// 开始测试
v = ;
i = search_upgrade(b, LEN(b), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(b, LEN(b), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(b, LEN(b), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(b, LEN(b), v);
printf("%d -> %d\n", v, i); v = ;
i = search_upgrade(b, LEN(b), v);
printf("%d -> %d\n", v, i); return EXIT_SUCCESS;
}

当前输出结果如下

$ gcc -g -Wall sort.c ; ./a.out

 ->
->
-> -
->
-> - ->
->
->
->
-> -

后记 - 感谢

错误是难免的 ~ 欢迎指正 : )

小桥 - https://music.163.com/#/song?id=493042772

C基础 旋转数组查找题目的更多相关文章

  1. leetcode旋转数组查找 二分查找的变形

    http://blog.csdn.net/pickless/article/details/9191075 Suppose a sorted array is rotated at some pivo ...

  2. leetcode python 033 旋转数组查找

    ## 假设升序,import random def find(y):    l,m=len(y),0    while l>1:        n=int(l/2)        if y[0] ...

  3. (剑指Offer)面试题8:旋转数组的最小数字

    题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转 ...

  4. (2)剑指Offer之二维数组查找和替换空格问题

    一 二维数组查找 题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 问 ...

  5. 剑指offer—第二章算法之二分查找(旋转数组的最小值)

    旋转数组的最小数字 题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如:数组{3,4,5,1,2}为{1,2,3,4, ...

  6. 剑指offer 6.查找和排序 旋转数组的最小数字

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  7. 28.earch in Rotated Sorted Array(排序旋转数组中查找)

    Level:   Medium 题目描述: Suppose an array sorted in ascending order is rotated at some pivot unknown to ...

  8. leetcode题解:Search in Rotated Sorted Array(旋转排序数组查找)

    题目: Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7  ...

  9. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

随机推荐

  1. Gson获取json串中的key-value

    1.依赖包 <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson& ...

  2. Alpha 完结撒花 —— 事后诸葛亮

    写在前面 林燊大哥 一路走来,好不容易,终于完结了. 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 解决的问题 用户在进店之前无法得知店铺的优劣,通过 ...

  3. 构建工具-----Gradle-----安装配置

    介绍 Gradle 是一款构建工具,继 Ant .Maven 之后的现代构建工具. 下载 Gradle 下面是 Gradle 的官方网站地址: Gradle l Modern Open-Source ...

  4. Error while uploading slice_4.apk : WARNING: linker: libhoudini.so has text relocations. This is wasting memory and prevents security hardening. Please fix.

    问题: android studio 2.4版本新建项目后老是编译不过,查看log报如下错误,最后发现关闭即时编译功能可以解决此问题.这也算是2.4测试版的bug吧 android - Error w ...

  5. 解题:SCOI 2010 序列操作

    题面 线段树......模板题(雾? 然而两种标记会互相影响,必须保证每次只放一个(不然就不知道怎么放了),具体的影响就是: 翻转标记会使得覆盖标记一起翻转,下放的时候就是各种swap 覆盖标记会抹掉 ...

  6. 微服务Kong(一)——简介

    重要提示: 本教程是根据 KONG 0.10.x 版本进行编写的. 一.什么是KONG Kong是一个可扩展的开源API层(也称为API网关或API中间件).它运行在任何RESTful API之前,并 ...

  7. lumen 使用 dingo API 在 phpunit 中 404 的解决方法, 以及鉴权问题

    1. phpunit.xml 中添加 dingo 相关配置 <env name="API_STANDARDS_TREE" value="x"/> & ...

  8. Ansible12:lookup

    目录 简单说明 1.file 2.pipe 3.env 4.template 5.csvfile 6.redis_kv 7.etcd 8.password 9.dnstxt 简单说明 在通常情况下,所 ...

  9. 数据分析与展示---Matplotlib入门

    简介: 一:Matplotlib库的介绍 (一)简单使用 二:区域划分subplot 三:plot函数 四:pyplot的中文显示 (一)方法一:修改rcParams参数 (二)方法二(推荐),在有中 ...

  10. python---基础知识回顾(十一)图像处理模块PIL

    前戏: 虽然PIL没有入OpenCV那样强大的功能,但是所提供的功能,在一般的图像处理中足够使用. 图像类别: 计算机绘图中有两类图像:一类是矢量图,另一类是点阵图(位图) 矢量图:基于计算机数字对象 ...