剑指Offer - 面试题11:旋转数组的最小数字

简介: 剑指Offer - 面试题11:旋转数组的最小数字

题目

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


分析

暴力法

我们不考虑任何特点,直接一次循环求解。

C

#include<stdio.h>
#include<stdlib.h>
int Min(int* n, int length)
{
  int min = INT_MAX;
  int i = 0;
  for (i = 0; i < length; i++)
  {
    if (n[i] < min)
    {
      min = n[i];
    }
  }
  return min;
}
int main()
{
  int p[5] = { 3,4,5,1,2 };
  int size = 5;
  int ret = Min(p, size);
  printf("最小值为:%d\n", ret);
  return 0;
}

二分法

我们可以将这个旋转过后的数组,分成俩个递增子数组。

但是还存在一种特殊情况旋转后的数组和原数组相同

总共有俩种情况


旋转后数组与原数组不相同

旋转后数组与原数组相同

设置start、end指针分别指向数组左右俩边,然后选取中间值mid = ((end - start)>>1 + start),防止溢出。

我们先选start指针做判断位置:


n[start] < n[mid] 在情况一中,mid位于左递增子数组,在情况二中mid位于右递增数组,所以我们换判断点

选end指针做判断位置:


n[end] < n[mid] 在情况一中,mid位于左递增子数组。在情况二中,不存在这种



  • n[end] > n[mid] 在情况一中,mid位于右递增子数组。在情况二中,mid位于右递增子数组


n[end] = n[[mid] 在情况一中,mid位于右递增子数组。在情况二中,mid位于右递增子数组。

  • C
#include<stdio.h>
#include<stdlib.h>
int Min(int* n, int length)
{
  if (n == NULL || length <= 0)
  {
    perror("");
    exit(EXIT_FAILURE);
  }
  int start = 0;
  int end = length - 1;
  while (start < end)
  {
    int mid = ((end - start) >> 1) + start;
    if (n[end] < n[mid])
    {
      start = mid + 1;
    }
    else if (n[end] > n[mid])
    {
      end = mid;
    }
    else
    {
      end--;
    }
  }
  return n[start];
}
int main()
{
  int n[10][5] = {
          {1,2,3,4,5},
          {2,3,4,5,1},
          {3,4,5,1,2},
          {4,5,1,2,3},
          {5,1,2,3,4},
          {1,1,1,2,2},
          {1,1,2,2,1},
          {1,2,2,1,1},
          {2,2,1,1,1},
          {1,1,2,2,2}, };
  int i = 0;
  for(i = 0; i< 10;i++)
  {
    int ret = Min(n[i],5);
    printf("min = %d\n", ret);
  }
  return 0;
}

最坏情况就是{1,1,1,1,1};相当于O(n)的时间复杂度,空间复杂度是常量O(1);

最好情况时间复杂度就是O(long2^N),空间复杂度是常量O(1);

我们也可以让n[end] = n[[mid] 相等时候直接遍历start到end 线性查找

#include<stdio.h>
#include<stdlib.h>
int Min(int* n, int length)
{
  if (n == NULL || length <= 0)
  {
    perror("");
    exit(EXIT_FAILURE);
  }
  int start = 0;
  int end = length - 1;
  while (start < end)
  {
    int mid = ((end - start) >> 1) + start;
    if (n[end] < n[mid])
    {
      start = mid + 1;
    }
    else if (n[end] > n[mid])
    {
      end = mid;
    }
    else
    {
      int m = start;//保存最小值小标
      for (++start; start < end; ++start)
      {
        if (n[m] > n[start])
        {
          m = start;
        }
      }
      return n[m];
    }
  }
  return n[start];
}
int main()
{
  int n[10][5] = {
          {1,2,3,4,5},
          {2,3,4,5,1},
          {3,4,5,1,2},
          {4,5,1,2,3},
          {5,1,2,3,4},
          {1,1,1,2,2},
          {1,1,2,2,1},
          {1,2,2,1,1},
          {2,2,1,1,1},
          {1,1,2,2,2}, };
  int i = 0;
  for(i = 0; i< 10;i++)
  {
    int ret = Min(n[i],5);
    printf("min = %d\n", ret);
  }
  return 0;
}


本章完!

目录
相关文章
|
4月前
|
C语言
【Amazon 面试题1】一个数组,里面得数出现的次数是偶数次,只有一个数出现的次数是奇数次,找出那个出现奇数次的数
本文介绍了解决Amazon面试题的一种方法,即在一个所有数字出现次数都是偶数,除了一个数字出现奇数次的数组中,利用异或运算的性质找出出现奇数次的数字,并提供了C语言实现的代码示例。
70 1
|
4月前
|
Java
Java 基础语法-面试题(54-63道)(数组+类+包)
Java 基础语法-面试题(54-63道)(数组+类+包)
46 16
|
4月前
|
安全 编译器 C++
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
|
5月前
|
存储 算法
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
|
6月前
|
开发框架 .NET
技术好文共享:面试题:找出数组中只出现一次的2个数(异或的巧妙应用)(出现3次)
技术好文共享:面试题:找出数组中只出现一次的2个数(异或的巧妙应用)(出现3次)
|
6月前
|
数据采集 算法 数据挖掘
LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】
LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
1月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
1月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
56 4