|
1 | 1 | /*
|
2 | | - * Copyright (C) 2017, Saul Lawliet <october dot sunbathe at gmail dot com> |
| 2 | + * Copyright (C) 2017-2022, Saul Lawliet <october dot sunbathe at gmail dot com> |
3 | 3 | * All rights reserved.
|
4 | 4 | *
|
5 | | - * 很好理解的写法, 以为性能可能不是最好的, 但耗时是第一梯队的. |
| 5 | + * https://leetcode.com/problems/search-in-rotated-sorted-array/ |
| 6 | + * Q: 在一个循环有序数组中(想象一个循环链表, 但起始位置可能不在数组头部), O(log n)的时间复杂度找到一个元素的位置 |
| 7 | + * |
| 8 | + * 看到题目, 就是要实现一个升级版本的二分查找, 接下来就要考虑如何计算 low 和 high |
| 9 | + * 第1步: 判断哪边是有序的 |
| 10 | + * 第2步: 找出异常情况: 要找的值在边界之外 |
| 11 | + * |
| 12 | + * 修改记录: |
| 13 | + * 2022年03月28日: 今天才发现, 之前没按规则实现, 于是重写了 |
| 14 | + * 2017年08月25日: 按照顺序查找实现的, 虽然AC并且耗时也是第一梯队的, 但代码不符合规则 |
6 | 15 | */
|
7 | 16 |
|
8 | | -#include <stdbool.h> |
9 | 17 | #include "c/data-structures/array.h"
|
10 | 18 | #include "c/test.h"
|
11 | 19 |
|
12 | | -void swap(int *a, int *b) { |
13 | | - int tmp = *a; |
14 | | - *a = *b; |
15 | | - *b = tmp; |
16 | | -} |
17 | | - |
18 | 20 | int search(int *nums, int numsSize, int target) {
|
19 | | - int index = -1; |
20 | | - for (int i = 0; i != numsSize; i++) { |
21 | | - if (index == -1 && nums[i] == target) { |
22 | | - index = i; |
23 | | - } |
24 | | - if (index != -1) { |
25 | | - for (int j = i; j != i - index; j--) { |
26 | | - swap(&nums[j], &nums[j-1]); |
| 21 | + int low = 0, high = numsSize - 1, mid; |
| 22 | + while (low <= high) { |
| 23 | + mid = (low + high) / 2; |
| 24 | + if (nums[mid] == target) |
| 25 | + return mid; |
| 26 | + |
| 27 | + if (nums[low] <= nums[mid]) { // 左侧有序 |
| 28 | + if (nums[mid] > target) { // 可能在左边 |
| 29 | + // 但特殊情况在右边 |
| 30 | + if (nums[low] > target) |
| 31 | + low = mid + 1; |
| 32 | + else |
| 33 | + high = mid - 1; |
| 34 | + } else { |
| 35 | + low = mid + 1; |
| 36 | + } |
| 37 | + } else { // 右侧有序 |
| 38 | + if (nums[mid] < target) { // 可能在右边 |
| 39 | + // 但特殊情况在左边 |
| 40 | + if (nums[high] < target) |
| 41 | + high = mid - 1; |
| 42 | + else |
| 43 | + low = mid + 1; |
| 44 | + } else { |
| 45 | + high = mid - 1; |
27 | 46 | }
|
28 | 47 | }
|
29 | 48 | }
|
30 | | - return index; |
| 49 | + return -1; |
31 | 50 | }
|
32 | 51 |
|
33 | | -void test(constchar*expect, int result, const char *str, int target) { |
34 | | - arrayEntry *e = arrayParse1D(str, ARRAY_INT); |
| 52 | +void test(int except, const char *nums, int target) { |
| 53 | + arrayEntry *e = arrayParse1D(nums, ARRAY_INT); |
35 | 54 |
|
36 | | - EXPECT_EQ_INT(result, search(arrayValue(e), arraySize(e), target)); |
37 | | - EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); |
| 55 | + EXPECT_EQ_INT(except, search(arrayValue(e), arraySize(e), target)); |
38 | 56 |
|
39 | 57 | arrayFree(e);
|
40 | 58 | }
|
41 | 59 |
|
42 | 60 | int main(void) {
|
43 | | - test("[4,5,6,7,0,1,2]", 3, "[0,1,2,4,5,6,7]", 4); |
| 61 | + test(4, "[4,5,6,7,0,1,2]", 0); |
| 62 | + test(-1, "[4,5,6,7,0,1,2]", 3); |
| 63 | + test(-1, "[1]", 0); |
| 64 | + |
| 65 | + // 以下是提交错误时的测试用例 |
| 66 | + test(0, "[3,5,1]", 3); |
| 67 | + test(2, "[5,1,3]", 3); |
| 68 | + test(0, "[5,1,3]", 5); |
| 69 | + test(4, "[4,5,6,7,8,1,2,3]", 8); |
| 70 | + test(1, "[3,1]", 1); |
44 | 71 |
|
45 | 72 | return testOutput();
|
46 | 73 | }
|
0 commit comments