Найти наименьшее число в сортированном вращающемся массиве
Я столкнулся с этим вопросом в одном интервью. Пожалуйста, помогите мне в решении проблемы.
Вопрос:
Вы отсортировали вращающийся массив, т.е. е. массив содержит элементы, которые сортируются и их можно вращать круговыми, например, если элементы в массиве [5,6,10,19,20,29], тогда вращающийся первый массив времени становится [29,5,6,10,19, 20], и во второй раз он становится [20,29,5,6,10,19] и т.д.
Итак, вам нужно найти наименьший элемент в массиве в любой точке. Вам не будет предоставлено число раз, когда массив вращается. Просто заданные вращающиеся элементы массива и узнать наименьшее среди них. В этом случае вывод должен быть 5.
Ответы
Ответ 1
Метод 1:
Вы можете сделать это в O(logN)
времени.
Используйте модифицированный двоичный поиск, чтобы найти точку вращения, которая является индексом i
таким образом, что arr[i] > arr[i+1]
.
Пример:
[6,7,8,9,1,2,3,4,5]
^
i
Два под-массива (arr[1], arr[2], .., arr[i])
и (arr[i+1], arr[i+2], ..., arr[n])
сортируются.
Ответ: min(arr[1], arr[i+1])
Метод 2:
Когда вы разбиваете отсортированный, повернутый массив на две половины (arr[1],..,arr[mid])
и (arr[mid+1],..,arr[n])
, один из них всегда сортируется, а другой всегда имеет мин. Мы можем напрямую использовать модифицированный двоичный поиск, чтобы продолжать поиск в несортированной половине
// index of first element
l = 0
// index of last element.
h = arr.length - 1
// always restrict the search to the unsorted
// sub-array. The min is always there.
while (arr[l] > arr[h]) {
// find mid.
mid = (l + h)/2
// decide which sub-array to continue with.
if (arr[mid] > arr[h]) {
l = mid + 1
} else {
h = mid
}
}
// answer
return arr[l]
Ответ 2
Вышеупомянутый алгоритм терпит неудачу, если элемент данных повторяется как {8,8,8,8,8} или {1,8,8,8,8} или {8,1,8,8,8} или { 8,8,1,8,8} или {8,8,8,8,1}
// solution pasted below will work all test cases :)
//break the array in two subarray and search for pattern like a[mid]>a[mid+1]
// and return the min position
public static int smallestSearch(int[] array,int start,int end)
{
if(start==end)
return array.length;
int mid=(start+end)/2;
if(array[mid]>array[mid+1])
return min(mid+1,smallestSearch(array,start,mid),smallestSearch(array,mid+1,end));
else
return min(smallestSearch(array,start,mid),smallestSearch(array,mid+1,end));
}
public static int min(int a,int b)
{
if(a==b)
return a;
else if(a<b)
return a;
else
return b;
}
public static int min(int a,int b,int c)
{
if(a<c)
{
if(a<b)
{
return a;
}
else
{
return b;
}
}
else
{
if(b<c)
return b;
else
return c;
}
}
Ответ 3
Найти наименьшее число в отсортированном повернутом массиве: используя концепцию двоичного поиска
public class RotatedSortedArrayWithoutDuplicates1 {
public static void main(String[] args) {
int[] a = { 4, 6, 8, 10, 34, 56, 78, 1, 3 };
System.out.println(findMin(a));
}
private static int findMin(int[] a) {
if (a.length == 0 || a == null) {
return -1;
}
int start = 0;
int last = a.length - 1;
while (start + 1 < last) {
int mid = start + (last - start) / 2;
int m = a[mid];
int s = a[start];
int l = a[last];
if (m > l) {
start = mid + 1;
}
if (m < l) {
last = mid;
} else {
last--;
}
} // while
if (a[start] > a[last]) {
return a[last];
} else {
return a[start];
}
}
}
Но если вы не хотите использовать бинарный поиск, то:
public class Abc {
public static void main(String[] args) {
int[] a = { 4, 5, 6, 7, 7, 8, 9, 1, 1, 2, 3, 3 };
System.out.println(findMin(a));
}
public static int findMin(int[] a) {
int min = a[a.length - 1];
for (int i = 0; i < a.length; i++) {
if (min > a[i]) {
min = a[i];
break;
}
}
return min;
}// findmin
}// end
Вот код в Python:
def fix(a):
min = a[0]
for i in range(len(a)):
if(min > a[i]):
min = a[i]
break
return min
a = [2, 2,3,4,1,2]
print(fix(a))
Ответ 4
Мой код ниже с алгоритмом в виде комментариев. Работает даже для повторяющихся элементов.
//Find Min in Rotated Sorted Array
//Example: int array[10] = {7, 8, 9, 10, 11, 12, 3, 4, 5, 6};
// Min in the above array is 3
// Solution: Recursively search (Modified binary search) for the Pivot where is the smallest Element is present
// Algorithm:
// 1) Find the Mid of the Array
// 2) call the recursive function on segment of array in which there is a deviation in the order
// If (A[low] > A[mid]) array segment in which deviation in the order present is (low, mid)
// If (A[low] < A[mid]) array segment in which deviation in the order present is (mid + 1, high)
// Time Complexity: O(logn)
// Space Complexity: is of the recursive function stack that is being used
#define MIN(x,y) (x) <= (y) ? (x): (y)
int MininRotatedSortedArray(int A[], int low, int high)
{
if(low > high)
return -1;
if(low == high - 1)
return MIN(A[low], A[high]);
int mid = low + (high - low)/2;
if(A[low] > A[mid])
return MininRotatedSortedArray(A, low, mid);
else if(A[low] < A[mid])
return MininRotatedSortedArray(A, mid + 1, high);
else
return A[mid];
}
Ответ 5
Это можно сделать в наилучшем случае времени O (1), в худшем случае времени O (n) и в среднем O (lg n).
Для вращающегося сортированного массива, если первый элемент в массиве меньше последнего элемента в массиве, сортированный массив не поворачивается (или не поворачивается на 0 позицию). Минимальный элемент - это просто первый элемент.
Если средний элемент меньше последнего элемента, то минимальный элемент находится в [первом, среднем].
Если средний элемент больше последнего элемента, то минимальный элемент находится в [middle + 1, last].
Если средний элемент равен последнему элементу, то есть два подсектора:
- первый элемент больше последнего элемента, в этом случае минимальный элемент находится в [first, middle + 1];
- первый элемент равен последнему элементу, и в этом случае неубедительно отклонить либо половину массива. Уменьшить до линейного поиска. Например, для массивов, таких как [5,5,5,1,5] и [5,1,5,5,5], невозможно просто изучить первый, последний и средний элементы (поскольку все они равны), в какой половине массива лежит минимальный элемент.
Я написал следующий код на С++ для решения этой проблемы, который должен обрабатывать все случаи (пустой массив, повторяющиеся элементы).
template <typename Iterator>
Iterator rotated_min(Iterator begin, Iterator end)
{
while (begin != end)
{
if (*begin < *(end - 1))
{
return begin;
}
Iterator mid = begin + (end - 1 - begin) / 2;
if (*mid < *(end - 1))
{
end = mid + 1;
}
else if (*mid > *(end - 1))
{
begin = mid + 1;
}
else
{
if (*begin > *(end - 1))
{
end = mid + 1;
++begin;
}
else
{
//reduce to linear search
typename ::std::iterator_traits<Iterator>::value_type min_value = *begin;
Iterator min_element = begin;
for (Iterator i = begin + 1; i != end; ++i)
{
if (*i < min_value)
{
min_value = *i;
min_element = i;
}
}
return min_element;
}
}
}
return begin;
}
Ответ 6
Найти индекс Min в круговом отсортированном массиве
Example : [7,8,9,1,2,3,4,5,6]
int findMinIndex(int []a, int start, int end)
{
int mid = (start + end)/2;
if (start - end == 1)
if(a[start] < a[end])
return start;
else
return end;
if (a[mid] > a[end]){
return findMinIndex(a,mid,end);
}
else{
return findMinIndex(a,start,mid);
}
return -1; //Not found
}
Ответ 7
В случае, если кому-то это нужно. Моя реализация в java..
заботится о сортировке/несортированном возрастании//порядке убывания usecases..
Недостатком является то, что он все равно выполнит шаги log n, чтобы найти минимальное значение в отлично отсортированном наборе без вращения.
http://ideone.com/fork/G3zMIb
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
int [] a = {3,3,0,2,2,2,2,1,2,2,2,2,2,2,2,2,2};
System.out.println(recursiveSplit(a,0,a.length-1));
}
public static int findMin(int x, int y){
if(x<=y){
return x;
}else{
return y;
}
}
public static int recursiveSplit(int[] arr , int a , int b){
int mid = (int) Math.floor(a + (b-a)/2);
int h1_l = a;
int h1_u = mid;
int h2_l = mid+1;
int h2_u = b;
int x=0;
int y=0;
//single element
if(a==b){
return arr[a];
}
//adjacent positions
if(h1_u-h1_l==1){
x=findMin(arr[h1_u],arr[h1_l]);
}else{
//else split
x=recursiveSplit(arr,h1_l,h1_u);
}
if(h2_u-h2_l==1){
y=findMin(arr[h2_u],arr[h2_l]);
}else{
y=recursiveSplit(arr, h2_l,h2_u);
}
return findMin(x, y);
}
}
Ошибки/предложения/неудачные usecases приветствуются
Ответ 8
public int findMin(int[] num) {
return findMin(num, 0, num.length-1);
}
public int findMin(int[] num, int left, int right){
if(left==right) return num[left];
if(left+1==right) return Math.min(num[left], num[right]);
int mid = (left+right)/2;
if(num[mid]>num[right]){
return findMin(num,mid+1,right);
}else if(num[mid]<num[right]){
return findMin(num,left,mid);
}else{
if(num[mid]==num[left]){
return Math.min(findMin(num,left,mid), findMin(num,mid,right));
}else{
return findMin(num,left,mid);
}
}
}
Ответ 9
Следующий алгоритм принимает log (n) время. Предполагая, что массив не имеет дубликатов.
public int findMin(int[] num) {
if(num.length == 0) return -1
int r = num.length-1, l = 0;
while(l<r){
if(num[l]<=num[r]) return num[l]; //when not rotated, return the left most value
int mid = (r+l)/2;
if(num[mid]<num[r]){
r = mid;
}else{
l = mid+1;
}
}
return num[l];
}
Ответ 10
Я сделал это, используя слегка модифицированную версию бинарного поиска. То, что я здесь делаю, я продолжаю идти влево или вправо, основываясь на том, где может быть минимум. Например, в восходящем массиве, если средний элемент меньше самого левого элемента, возможно, что минимум находится слева. Во время рекурсии через массив я также отслеживаю минимум. Рекурсия продолжается до конца, а затем возвращается последний мин. Это также работает с повторяющимися элементами.
public static void main(String[] args) throws IOException {
int[] rotated = {6, 7, 8, 1, 2, 3, 4, 5};
int min = findMin(rotated);
System.out.println(min);//1
}
public static int findMin(int[] sorted) {
return findMinRecursively(sorted, sorted[0], 0, (sorted.length - 1));
}
private static int findMinRecursively(int[] sorted, int min, int leftIndex, int rightIndex) {
if (leftIndex > rightIndex) {
return min;
}
int midIndex = (leftIndex + rightIndex) / 2;
if (sorted[midIndex] < min) {
min = sorted[midIndex];
}
if (sorted[midIndex] < sorted[leftIndex]) {
return findMinRecursively(sorted, min, leftIndex, (midIndex - 1));
} else {
return findMinRecursively(sorted, min, (midIndex + 1), rightIndex);
}
}
Ответ 11
Вопрос: Найти минимум в отсортированном повернутом массиве. Решение 1. Использование бинарного поиска
class Test18 {
public static void main(String[] args) {
int[] a = { 5, 6, 7, 8, 9, 10, 1, 2, 3 };
System.out.println(findmin(a));
}
// find min in a sorted rotated array
private static int findmin(int[] a) {
int start = 0;
int last = a.length - 1;
while (start + 1 < last) {
int mid = start + (last - start) / 2;
if (a[mid] > a[last]) {
start = mid + 1;
}
if (a[mid] < a[last]) {
last = mid;
} else {
mid--;
}
} // while
if (a[start] > a[last]) {
return a[last];
} else {
return a[start];
}
}
}
Ответ 12
def searchinrotatedarray(arr1,l,h):
if l>h:
return arr1[0]
if h==l:
return arr1[l]
mid=(l+h)//2
if mid<h and arr1[mid+1]<arr1[mid]:
return arr1[mid+1]
elif mid>l and arr1[mid-1]<arr1[mid]:
return arr1[mid]
elif arr1[mid]<arr1[h]:
return searchinrotatedarray(arr1,l,mid-1)
else:
return searchinrotatedarray(arr1,mid+1,h)
первый оператор if проверяет, вращается ли хотя бы массив. в этом случае первым элементом является мин. если длина списка равна 1, то этот элемент мин. иначе, если средний элемент меньше, чем последний элемент, тогда продолжайте искать во второй половине, иначе ищите элемент в первой половине
Ответ 13
//java program to find minimum element in a sorted array rotated
//about any pivot in O(log n) in worst case and O(1) in best case
class ArrayRotateMinimum {
public static void main(String str[]) {
// initialize with your sorted rotated array here
int array[] = { 9, 1, 2, 3, 4, 5, 6, 7, 8, };
System.out.println("Minimum element is: " + minimumElement(array));
}
static int minimumElement(int array[]) {
// variables to keep track of low and high indices
int low, mid, high;
// initializing variables with appropriate values
low = 0;
high = array.length - 1;
while (low < high) {
// mid is always defined to be the average of low and high
mid = (low + high) / 2;
if (array[low] > array[mid]) {
// for eg if array is of the form [9,1,2,4,5],
// then shift high to mid to reduce array size by half
// while keeping minimum element between low and high
high = mid;
} else if (array[mid] > array[high]) {
// this condition deals with the end case when the final two
// elements in the array are of the form [9,1] during the
// last iteration of the while loop
if (low == mid) {
return array[high];
}
// for eg if array is of the form [4,5,9,1,2],
// then shift low to mid to reduce array size by half
// while keeping minimum element between low and high
low = mid;
} else {
// the array has not been rotated at all
// hence the first element happens to be the smallest element
return array[low];
}
}
//return first element in case array size is just 1
return array[0];
}
}
Ответ 14
Это моё питоническое решение с использованием рекурсии:
Временная сложность составляет O (log (n)) & Пространство сложности: O (1)
class Solution(object):
def findMin(self, nums):
left = 0
right = len(nums) -1
mid = len(nums) // 2
if len(nums) == 0:
return -1
if len(nums) == 1:
return nums[left]
if len(nums) == 2:
return min(nums[left], nums[right])
if nums[left] < nums[right]:
return nums[left]
elif nums[mid] > nums[left]:
return self.findMin(nums[mid + 1: ])
elif nums[mid] < nums[left]:
return self.findMin(nums[: mid + 1])