C基础 旋转数组查找题目
前言 - 引言
题目:
一类有序数组旋转查值问题.
例如:
有序数组 [ , , , , , , , , ] 旋转后为 [ , , , , , , , , ]
如何从中找出一个值索引, 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基础 旋转数组查找题目的更多相关文章
- leetcode旋转数组查找 二分查找的变形
http://blog.csdn.net/pickless/article/details/9191075 Suppose a sorted array is rotated at some pivo ...
- leetcode python 033 旋转数组查找
## 假设升序,import random def find(y): l,m=len(y),0 while l>1: n=int(l/2) if y[0] ...
- (剑指Offer)面试题8:旋转数组的最小数字
题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转 ...
- (2)剑指Offer之二维数组查找和替换空格问题
一 二维数组查找 题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 问 ...
- 剑指offer—第二章算法之二分查找(旋转数组的最小值)
旋转数组的最小数字 题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如:数组{3,4,5,1,2}为{1,2,3,4, ...
- 剑指offer 6.查找和排序 旋转数组的最小数字
题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...
- 28.earch in Rotated Sorted Array(排序旋转数组中查找)
Level: Medium 题目描述: Suppose an array sorted in ascending order is rotated at some pivot unknown to ...
- 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 ...
- Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
随机推荐
- [BZOJ4446]SCoi2015 小凸玩密室 树形DP(烧脑高能预警)
4446: [Scoi2015]小凸玩密室 Time Limit: 10 Sec Memory Limit: 128 MB Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点 ...
- R1 学习记录
libevent框架学习特点: 1.可移植行,跨平台的 2.速度快,libevent会用各平台最快的非阻塞IO函数 3.扩展性 4.方便性构成: 1.evutil: 抽象出各平台network的函数 ...
- CentOS7单节点部署redis-cluster
准备一台机器,系统版本为CentOS7.(注意本文描述的是redis-cluster,不是主从复制) 1.下载软件包 # wget http://download.redis.io/releases/ ...
- PHP发送HTTP请求的几种方式
转发:https://blog.tanteng.me/2017/07/php-curl-guzzlehttp/ 1)PHP开发中我们常用CURL 方式封装 HTTP请求,什么是CURL? CURL 是 ...
- 梯度提升树GBDT算法
转自https://zhuanlan.zhihu.com/p/29802325 本文对Boosting家族中一个重要的算法梯度提升树(Gradient Boosting Decison Tree, 简 ...
- GDB调试工具
1.运行代码的三种情况 a.运行时有逻辑问题 gdb a.out 设置断点 单行执行 b.运行代码没有退出 一直运行 结束不了 挂载调试 跟踪调试 -g ...
- cuckoo 安装
最新 https://www.jianshu.com/p/f623fa0bebf9 http://www.freebuf.com/articles/system/123816.html http:// ...
- google analysis教程
sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction.htm?courseId=1005269003&utm_campai ...
- SecureCRT无法使用root正常连接Ubuntu 14.0.4.1的解决办法
问题描述 通过VirtualBox重新安装了Ubuntu 14.0.4.1 虚拟服务器,在SercureCRT中使用root帐号连接Ubuntu14.0.4.1的时候,提示“Password Auth ...
- js 正则表达式 整数或小数
非零开头的整数或小数 /^[1-9][0-9]*([.][0-9]+)?$/ 非零开头的整数或两位小数 /^[1-9][0-9]*([.][0-9]{1,2})?$/ /^[1-9][0-9]*([. ...