정렬 및 회전 된 배열에서 검색


79

인터뷰를 준비하는 동안 다음과 같은 흥미로운 질문을 발견했습니다.

정렬 된 다음 회전 된 배열이 주어졌습니다.

예를 들면 :

  • arr = [1,2,3,4,5]정렬 된 Let ,
  • 제공하려면 오른쪽으로 두 번 회전하십시오 [4,5,1,2,3].

이제이 정렬 된 + 회전 된 배열에서 하나의 검색이 얼마나 최선일까요?

배열을 회전 해제 한 다음 이진 검색을 수행 할 수 있습니다. 그러나 둘 다 최악의 경우 O (N)이기 때문에 입력 배열에서 선형 검색을 수행하는 것보다 낫지 않습니다.

몇 가지 지침을 제공하십시오. 나는 이것에 대한 특별한 알고리즘을 많이 봤지만 아무것도 찾을 수 없었다.

C와 C ++를 이해합니다.


9
숙제라면 homework태그 를 추가 해주세요 . 그러면 사람들이 붙여 넣을 수있는 답변을 게시하는 대신 올바른 방향으로 부드럽게 넛지하도록 유도 할 수 있습니다.
— sbi 2011 년

3
어레이가 회전 된 횟수를 알고 있습니까?
— Yochai Timmer 2011 년

2
그 크기의 배열에 대해서는 전혀 걱정할 필요가 없습니다. 당신의 진짜 문제는 무엇입니까?
— sbi 2011 년

3
아니, 숙제가 아닙니다. 나는 회전 수를 모른다. 그리고 그 예는 단순하게 유지되었습니다. 배열에는 수백만 개의 요소가있을 수 있습니다.
— Jones

1
배열에는 항상 1부터 시작하는 순차 값이 있습니까? 아니면 (중복 포함) 무엇이든 가질 수 있습니까?
— The Archetypal Paul

답변:


210

이것은 O(logN)약간 수정 된 이진 검색 을 사용하여 수행 할 수 있습니다 .

정렬 된 + 회전 된 배열의 흥미로운 속성은 두 개의 절반으로 나눌 때 두 절반 중 적어도 하나가 항상 정렬된다는 것입니다.

Let input array arr = [4,5,6,7,8,9,1,2,3]
number of elements  = 9
mid index = (0+8)/2 = 4

[4,5,6,7,8,9,1,2,3]
         ^
 left   mid  right

오른쪽 하위 배열은 정렬되지 않고 왼쪽 하위 배열은 정렬됩니다.

중간이 회전 지점 인 경우 왼쪽 및 오른쪽 하위 배열이 모두 정렬됩니다.

[6,7,8,9,1,2,3,4,5]
         ^

그러나 어쨌든 반 (하위 배열)은 정렬되어야합니다 .

각 절반의 시작 요소와 끝 요소를 비교하여 어느 절반이 정렬되었는지 쉽게 알 수 있습니다.

정렬 된 절반을 찾으면 그 절반에 키가 있는지 확인할 수 있습니다. 극단과의 간단한 비교입니다.

그 절반에 키가 있으면 우리는 그 절반에 대한 함수를
재귀 적으로 호출하고 나머지 절반에 대한 검색을 재귀 적으로 호출합니다.

우리는이 알고리즘을 만드는 각 호출에서 배열의 절반을 버립니다 O(logN).

의사 코드 :

function search( arr[], key, low, high)

        mid = (low + high) / 2

        // key not present
        if(low > high)
                return -1

        // key found
        if(arr[mid] == key)
                return mid

        // if left half is sorted.
        if(arr[low] <= arr[mid])

                // if key is present in left half.
                if (arr[low] <= key && arr[mid] >= key) 
                        return search(arr,key,low,mid-1)

                // if key is not present in left half..search right half.
                else                 
                        return search(arr,key,mid+1,high)
                end-if

        // if right half is sorted. 
        else    
                // if key is present in right half.
                if(arr[mid] <= key && arr[high] >= key) 
                        return search(arr,key,mid+1,high)

                // if key is not present in right half..search in left half.
                else
                        return search(arr,key,low,mid-1)
                end-if
        end-if  

end-function

여기서 핵심은 하나의 하위 배열이 항상 정렬되어 배열의 절반을 버릴 수 있다는 것입니다.


3
단순한. 간결한. 예. FTW !!
— Ashwin

이것이 제가 Stackoverflow를 좋아하는 이유입니다. 항상 문제를 해결하기위한 새롭고 최상의 접근 방식을 얻습니다. 감사 @codeaddict
— 바라트 SONI

3
"15"를 검색하는 것과 같이 중복 된 어레이를 찾지 못하므로 중복을 수용하기위한 솔루션의 변경 사항은 무엇입니까 {10, 15, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}?
— Shadab Ansari

@ShadabAnsari 나는 그것이 완전히 다른 대답이 될 것이라고 생각합니다. 정렬 된 하위 배열에만 집중할 수 있으므로 중첩 된 조건을 따르는 것이 더 쉽습니다. 어레이의 일부가 아닌 전체 어레이에 대해 생각하는 데 문제가있었습니다.
— Ehtesh Choudhury

4
"정렬 + 회전 배열의 흥미로운 특성은 두 개의 반으로 나눌 때 두 반쪽 중 적어도 하나가 항상 정렬된다는 것입니다." 이것은 천재 또는 경험이 초보자와 분리됩니다. 감사합니다.이 한 줄은 전체 솔루션을 시각화하는 데 도움이되었습니다.
— wild_nothing jul.

21

허용되는 답변에는 배열에 중복 요소가있을 때 버그가 있습니다. 예를 들어, arr = {2,3,2,2,2}3은 우리가 찾고있는 것입니다. 그런 다음 수락 된 답변의 프로그램은 1 대신 -1을 반환합니다.

이 인터뷰 질문은 'Cracking the Coding Interview'책에 자세히 설명되어 있습니다. 중복 요소의 조건은 그 책에서 특별히 논의됩니다. op가 주석에서 배열 요소가 무엇이든 될 수 있다고 말 했으므로 아래의 의사 코드로 솔루션을 제공하고 있습니다.

function search( arr[], key, low, high)

    if(low > high)
        return -1

    mid = (low + high) / 2

    if(arr[mid] == key)
        return mid

    // if the left half is sorted.
    if(arr[low] < arr[mid]) {

        // if key is in the left half
        if (arr[low] <= key && key <= arr[mid]) 
            // search the left half
            return search(arr,key,low,mid-1)
        else
            // search the right half                 
            return search(arr,key,mid+1,high)
        end-if

    // if the right half is sorted. 
    else if(arr[mid] < arr[low])    
        // if the key is in the right half.
        if(arr[mid] <= key && arr[high] >= key) 
            return search(arr,key,mid+1,high)
        else
            return search(arr,key,low,mid-1)
        end-if

    else if(arr[mid] == arr[low])

        if(arr[mid] != arr[high])
            // Then elements in left half must be identical. 
            // Because if not, then it's impossible to have either arr[mid] < arr[high] or arr[mid] > arr[high]
            // Then we only need to search the right half.
            return search(arr, mid+1, high, key)
        else 
            // arr[low] = arr[mid] = arr[high], we have to search both halves.
            result = search(arr, low, mid-1, key)
            if(result == -1)
                return search(arr, mid+1, high, key)
            else
                return result
   end-if
end-function

11
반복되는 요소를 제대로 고려한 건 당신 뿐인 것 같아요. 그러나 귀하의 접근 방식은 대수 복잡성을 보장하지 않습니다. 특히 5,5,5,5,5,5, ... (많은 수정 사항), 5,1, 5와 같은 입력에서
— Tomato

반복되는 요소가있는 경우 시간 복잡도는 얼마입니까?
— 프라 샨스 Debbadwar

중복이 허용되면 선형이어야한다고 생각합니다. 어딘가에 1하나가 2있는 N 의 목록을 고려하십시오 . 어디에나있을 수 있으며 유효한 입력이됩니다. 우리는 그것을 찾고 2있습니다. 우리가 고려하는 M> 2 숫자의 범위에 상관없이, 그것이 어느 쪽에도 없다면 2우리는 그것이 M 숫자에 포함되어 있는지 여부를 알 수 없습니다. 따라서 도움이되는 방식으로 검색 범위를 좁힐 수 없습니다.
— Sopel

18

인덱스를 찾을 수 첫째 : 당신은 2 개 진 검색 할 수있는 i그러한를 arr[i] > arr[i+1].

분명히, (arr\[1], arr[2], ..., arr[i])그리고 (arr[i+1], arr[i+2], ..., arr[n])둘 다 정렬 된 배열입니다.

그런 다음 arr[1] <= x <= arr[i]첫 번째 배열에서 이진 검색을 수행하고 그렇지 않으면 두 번째 배열에서 이진 검색을 수행합니다.

복잡성 O(logN)

편집 : 코드 .


감사합니다.하지만 첫 BS를 어떻게 적용 할 것인지 이해가 안 되나요?
— Jones

검색 키는 무엇입니까?
— Jones

@Jones, 코드를 작성하고 설명하는 것이 더 쉽습니다. 나는 대답을 편집하고 링크를 찾으십시오.
— Max

4
"중단 점"을 명시 적으로 검색해야하는 이유는 무엇입니까? 수정 된 이진 검색을 직접 사용하여 요소를 검색하는 동시에 "이상"을 확인하지 않는 이유는 무엇입니까?
— ruslik 2011 년

나는 여기에 늦었고 동일한 질문을 받았으며 O (logn)에서 해결하지 않았으며 내 솔루션은 O (n)에서 약간 개선되었습니다. 내 접근 방식은 두 포인터 i = 0 및 j = size ()-1, 루프 확인 arr [i] == 키 또는 arr [j] == 키가 발견되면 i 또는 j를 반환하고 중단하고 그렇지 않으면 icrement i 및 감소 j, 중단 조건은 i <j였습니다.이 경우 루프는 키가 중간에 있으면 최악의 경우 n / 2 시간 동안 실행됩니다
— Jaydeep Shil

8

내 첫 번째 시도는 이진 검색을 사용하여 적용된 회전 수를 찾는 것입니다. 이것은 일반적인 이진 검색 메커니즘을 사용하여 a [n]> a [n + 1] 인 인덱스 n을 찾아서 수행 할 수 있습니다. 그런 다음 찾은 시프트 당 모든 인덱스를 회전하면서 일반 이진 검색을 수행합니다.


부패 수를 찾기 위해 BS를 수행 할 때 검색 키는 무엇입니까?
— 존스

2
@Jones : 수정 된 이진 검색입니다. 두 개의 인접한 값이 감소하는 지점을 찾고 있습니다. 색인을 맞춰보세요. 해당 인덱스의 값이 배열의 첫 번째 값보다 크면 추측의 오른쪽을 계속 찾으십시오. 더 적 으면 계속 왼쪽을 봅니다. 그러나 대구 중독자의 대답은 실제로 불연속성이 어디에 있는지 신경 쓰지 않고 검색을 수행하고 싶을 때 더 좋습니다 .
— Steve Jessop 2011 년

5
int rotated_binary_search(int A[], int N, int key) {
  int L = 0;
  int R = N - 1;

  while (L <= R) {
    // Avoid overflow, same as M=(L+R)/2
    int M = L + ((R - L) / 2);
    if (A[M] == key) return M;

    // the bottom half is sorted
    if (A[L] <= A[M]) {
      if (A[L] <= key && key < A[M])
        R = M - 1;
      else
        L = M + 1;
    }
    // the upper half is sorted
    else {
      if (A[M] < key && key <= A[R])
        L = M + 1;
      else
        R = M - 1;
    }
  }
  return -1;
}

위에서 언급했듯이 이것은 중복 항목의 경우를 처리하지 않습니다. 그러나 요소가 고유 한 경우 재귀를 수행하지 않으므로 매우 간단한 코드입니다.
— kaushal

3

배열이 s 오른쪽으로 회전 된 것을 알고 있다면 s를 오른쪽으로 이동시킨 이진 검색을 수행 할 수 있습니다. 이것은 O (lg N)

즉, 왼쪽 제한을 ​​s로, 오른쪽을 (s-1) mod N으로 초기화하고 이진 검색을 수행하여 올바른 영역에서 작업하기 위해 약간의주의를 기울입니다.

배열이 얼마나 회전했는지 모르는 경우 이진 검색 (O (lg N))을 사용하여 회전의 ​​크기를 확인한 다음 이동 이진 검색, O (lg N), a 여전히 O (lg N)의 총합.


2

얼마나 (멀리) 회전했는지 안다면 이진 검색을 할 수 있습니다.

비결은 두 가지 수준의 인덱스를 얻는 것입니다. 가상 0..n-1 범위에서 bs를 수행 한 다음 실제로 값을 찾을 때 회전을 해제합니다.


2

위에서 언급 한 게시물에 대한 답글 "이 인터뷰 질문은 'Cracking the Coding Interview'책에서 자세히 논의됩니다. 중복 요소의 조건은 해당 책에서 특별히 논의됩니다. op가 코멘트에서 배열 요소는 무엇이든 될 수 있다고 말했기 때문에 저는 내 솔루션을 아래의 의사 코드로 제공하고 있습니다. "

귀하의 솔루션은 O (n) !! (단일 조건에 대해 배열의 절반을 모두 확인하는 마지막 if 조건은 선형 시간 복잡도의 솔이됩니다)

코딩 라운드 중에 버그와 세분화 오류의 미로에 갇히는 것보다 선형 검색을 수행하는 것이 좋습니다.

회전 정렬 된 배열 (중복 포함)에서 검색하는 경우 O (n)보다 더 나은 솔루션이 있다고 생각하지 않습니다.


2

먼저 배열을 회전 할 필요가 없습니다. 회전 된 배열에서 이진 검색을 사용할 수 있습니다 (일부 수정 포함).

N을 검색중인 번호로 지정하십시오.

첫 번째 숫자 (arr [start])와 배열 중간의 숫자 (arr [end])를 읽습니다.

  • arr [start]> arr [end]-> 첫 번째 절반은 정렬되지 않지만 두 번째 절반은 정렬됩니다.

    • arr [end]> N-> 숫자가 인덱스에있는 경우 : (middle + N-arr [end])

    • N이면 배열의 첫 번째 부분에서 검색을 반복합니다 (배열의 전반부 중간이되는 끝 참조).

(첫 번째 부분이 정렬되었지만 두 번째 부분이 정렬되지 않은 경우 동일)


1
public class PivotedArray {

//56784321 first increasing than decreasing
public static void main(String[] args) {
    // TODO Auto-generated method stub
    int [] data ={5,6,7,8,4,3,2,1,0,-1,-2};

    System.out.println(findNumber(data, 0, data.length-1,-2));

}

static int findNumber(int data[], int start, int end,int numberToFind){

    if(data[start] == numberToFind){
        return start;
    }

    if(data[end] == numberToFind){
        return end;
    }
    int mid = (start+end)/2;
    if(data[mid] == numberToFind){
        return mid;
    }
    int idx = -1;
    int midData = data[mid];
    if(numberToFind < midData){
        if(midData > data[mid+1]){
            idx=findNumber(data, mid+1, end, numberToFind);
        }else{
            idx =  findNumber(data, start, mid-1, numberToFind);
        }
    }

    if(numberToFind > midData){
        if(midData > data[mid+1]){
            idx =  findNumber(data, start, mid-1, numberToFind);

        }else{
            idx=findNumber(data, mid+1, end, numberToFind);
        }
    }
    return idx;
}

}

1
short mod_binary_search( int m, int *arr, short start, short end)
{

 if(start <= end)
 {
    short mid = (start+end)/2;

    if( m == arr[mid])
        return mid;
    else
    {
        //First half is sorted
        if(arr[start] <= arr[mid])
        {
            if(m < arr[mid] && m >= arr[start])
                return mod_binary_search( m, arr, start, mid-1);
            return mod_binary_search( m, arr, mid+1, end);
        }

        //Second half is sorted
        else
        {
            if(m > arr[mid] && m < arr[start])
                return mod_binary_search( m, arr, mid+1, end);
            return mod_binary_search( m, arr, start, mid-1);
        }
    }
 }
 return -1;
}

1

먼저 시프트 상수 k를 찾아야합니다. 이것은 O (lgN) 시간에 수행 될 수 있습니다. 상수 시프트 k에서 상수 k와 함께 이진 검색을 사용하여 원하는 요소를 쉽게 찾을 수 있습니다. 증강 이진 검색에도 O (lgN) 시간이 걸립니다. 총 실행 시간은 O (lgN + lgN) = O (lgN)입니다.

상수 이동을 구하려면 k. 배열에서 최소값을 찾아야합니다. 배열의 최소값 인덱스는 상수 이동을 알려줍니다. 정렬 된 배열 [1,2,3,4,5]를 고려하십시오.

가능한 이동은 다음과 같습니다.
    [1,2,3,4,5] // k = 0
    [5,1,2,3,4] // k = 1
    [4,5,1,2,3] // k = 2
    [3,4,5,1,2] // k = 3
    [2,3,4,5,1] // k = 4
    [1,2,3,4,5] // k = 5 % 5 = 0 

O (lgN) 시간에 알고리즘을 수행하려면 항상 문제를 절반으로 나누는 방법을 찾는 것이 중요합니다. 이렇게하면 나머지 구현 세부 사항은 간단합니다.

다음은 알고리즘에 대한 C ++ 코드입니다.

// This implementation takes O(logN) time
// This function returns the amount of shift of the sorted array, which is
// equivalent to the index of the minimum element of the shifted sorted array. 
#include <vector> 
#include <iostream> 
using namespace std; 

int binarySearchFindK(vector<int>& nums, int begin, int end)
{
    int mid = ((end + begin)/2); 
    // Base cases
    if((mid > begin && nums[mid] < nums[mid-1]) || (mid == begin && nums[mid] <= nums[end]))     
        return mid; 
    // General case 
    if (nums[mid] > nums[end]) 
    {
        begin = mid+1; 
        return binarySearchFindK(nums, begin, end); 
    }
    else
    {
        end = mid -1; 
        return binarySearchFindK(nums, begin, end); 
    }   
}  
int getPivot(vector<int>& nums)
{
    if( nums.size() == 0) return -1; 
    int result = binarySearchFindK(nums, 0, nums.size()-1); 
    return result; 
}

// Once you execute the above, you will know the shift k, 
// you can easily search for the element you need implementing the bottom 

int binarySearchSearch(vector<int>& nums, int begin, int end, int target, int pivot)
{
    if (begin > end) return -1; 
    int mid = (begin+end)/2;
    int n = nums.size();  
    if (n <= 0) return -1; 

    while(begin <= end)
    {
        mid = (begin+end)/2; 
        int midFix = (mid+pivot) % n; 
        if(nums[midFix] == target) 
        {
            return midFix; 
        }
        else if (nums[midFix] < target)
        {
            begin = mid+1; 
        }
        else
        {
            end = mid - 1; 
        }
    }
    return -1; 
}
int search(vector<int>& nums, int target) {
    int pivot = getPivot(nums); 
    int begin = 0; 
    int end = nums.size() - 1; 
    int result = binarySearchSearch(nums, begin, end, target, pivot); 
    return result; 
}
이것이 도움이되기를 바랍니다! =)
Soon Chee Loong, 
토론토 대학교 

1

중복 된 회전 배열의 경우 요소의 첫 번째 발생을 찾아야하는 경우 아래 절차 (Java 코드)를 사용할 수 있습니다.

public int mBinarySearch(int[] array, int low, int high, int key)
{
    if (low > high)
        return -1; //key not present

    int mid = (low + high)/2;

    if (array[mid] == key)
        if (mid > 0 && array[mid-1] != key)
            return mid;

    if (array[low] <= array[mid]) //left half is sorted
    {
        if (array[low] <= key && array[mid] >= key)
            return mBinarySearch(array, low, mid-1, key);
        else //search right half
            return mBinarySearch(array, mid+1, high, key);
    }
    else //right half is sorted
    {
        if (array[mid] <= key && array[high] >= key)
            return mBinarySearch(array, mid+1, high, key);
        else
            return mBinarySearch(array, low, mid-1, key);
    }       

}

이것은 위의 대구 중독자의 절차를 개선 한 것입니다. 추가 if 조건은 아래와 같습니다.

if (mid > 0 && array[mid-1] != key)

0

다음은 원래 배열을 수정하지 않는 간단한 (시간, 공간) 효율적인 비 재귀 O (log n) 파이썬 솔루션입니다. 두 개의 인덱스 만 확인할 때까지 회전 된 배열을 반으로 자르고 하나의 인덱스가 일치하면 정답을 반환합니다.

def findInRotatedArray(array, num):

lo,hi = 0, len(array)-1
ix = None


while True:


    if hi - lo <= 1:#Im down to two indices to check by now
        if (array[hi] == num):  ix = hi
        elif (array[lo] == num): ix = lo
        else: ix = None
        break

    mid = lo + (hi - lo)/2
    print lo, mid, hi

    #If top half is sorted and number is in between
    if array[hi] >= array[mid] and num >= array[mid] and num <= array[hi]:
        lo = mid

    #If bottom half is sorted and number is in between
    elif array[mid] >= array[lo] and num >= array[lo] and num <= array[mid]:
        hi = mid


    #If top half is rotated I know I need to keep cutting the array down
    elif array[hi] <= array[mid]:
        lo = mid

    #If bottom half is rotated I know I need to keep cutting down
    elif array[mid] <= array[lo]:
        hi = mid

print "Index", ix

0

이 솔루션 시도

bool search(int *a, int length, int key)
{
int pivot( length / 2 ), lewy(0), prawy(length);
if (key > a[length - 1] || key < a[0]) return false;
while (lewy <= prawy){
    if (key == a[pivot]) return true;
    if (key > a[pivot]){
        lewy = pivot;
        pivot += (prawy - lewy) / 2 ? (prawy - lewy) / 2:1;}
    else{
        prawy = pivot;
        pivot -= (prawy - lewy) / 2 ? (prawy - lewy) / 2:1;}}
return false;
}

0

C ++의이 코드는 모든 경우에 작동합니다. 중복 된 코드에서도 작동하지만이 코드에 버그가 있으면 알려주세요.

#include "bits/stdc++.h"
using namespace std;
int searchOnRotated(vector<int> &arr, int low, int high, int k) {

    if(low > high)
        return -1;

    if(arr[low] <= arr[high]) {

        int p = lower_bound(arr.begin()+low, arr.begin()+high, k) - arr.begin();
        if(p == (low-high)+1)
            return -1;
        else
            return p; 
    }

    int mid = (low+high)/2;

    if(arr[low] <= arr[mid]) {

        if(k <= arr[mid] && k >= arr[low])
            return searchOnRotated(arr, low, mid, k);
        else
            return searchOnRotated(arr, mid+1, high, k);
    }
    else {

        if(k <= arr[high] && k >= arr[mid+1])
            return searchOnRotated(arr, mid+1, high, k);
        else
            return searchOnRotated(arr, low, mid, k);
    }
}
int main() {

    int n, k; cin >> n >> k;
    vector<int> arr(n);
    for(int i=0; i<n; i++) cin >> arr[i];
    int p = searchOnRotated(arr, 0, n-1, k);
    cout<<p<<"\n";
    return 0;
}

0

자바 스크립트에서

var search = function(nums, target,low,high) {
    low= (low || low === 0) ? low : 0;

    high= (high || high == 0) ? high : nums.length -1;

    if(low > high)
        return -1;

    let mid = Math.ceil((low + high) / 2);


    if(nums[mid] == target)
        return mid;

    if(nums[low] < nums[mid]) {
        // if key is in the left half
        if (nums[low] <= target && target <= nums[mid]) 
            // search the left half
            return search(nums,target,low,mid-1);
        else
            // search the right half                 
            return search(nums,target,mid+1,high);
    } else {
        // if the key is in the right half.
        if(nums[mid] <= target && nums[high] >= target) 
            return search(nums,target,mid+1,high)
        else
            return search(nums,target,low,mid-1)
    }
};

입력 : nums = [4,5,6,7,0,1,2], target = 0 출력 : 4


0
import java.util.*;

class Main{
    public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt();
        int arr[]=new int[n];
        int max=Integer.MIN_VALUE;
        int min=Integer.MAX_VALUE;
        int min_index=0,max_index=n;

        for(int i=0;i<n;i++){
            arr[i]=sc.nextInt();
            if(arr[i]>max){
                max=arr[i];
            max_index=i;
            }
            if(arr[i]<min){
                min=arr[i];
                min_index=i;
            }

        }

        int element=sc.nextInt();
        int index;
        if(element>arr[n-1]){
            index=Arrays.binarySearch(arr,0,max_index+1,element);
        }
        else {
             index=Arrays.binarySearch(arr,min_index,n,element);
        }
        if(index>=0){
            System.out.println(index);
        }
        else{
            System.out.println(-1);
        }
    }

}

0

여기 내 두 센트가 있습니다.

  • 배열에 중복 항목 이 없으면 O (log (n))에서 솔루션을 찾을 수 있습니다. 많은 사람들이 사례를 보여 주었 듯이, 이진 검색의 조정 된 버전을 사용하여 대상 요소를 찾을 수 있습니다.

  • 그러나 배열에 중복이 포함되어 있으면 O (log (n))에서 대상 요소를 찾을 수있는 방법이 없다고 생각합니다. 다음은 O (log (n))가 불가능하다고 생각하는 이유를 보여주는 예입니다. 아래 두 배열을 고려하십시오.

a = [2,.....................2...........3,6,2......2]
b = [2.........3,6,2........2......................2]

모든 점은 숫자 2로 채워져 있습니다. 두 배열이 모두 정렬되고 회전 된 것을 볼 수 있습니다. 이진 검색을 고려하려면 반복 할 때마다 검색 영역을 절반으로 줄여야합니다. 이것이 O (log (n))를 얻는 방법입니다. 숫자 3을 검색한다고 가정 해 보겠습니다. 첫 번째 경우에는 배열의 오른쪽에 숨어 있고 두 번째 경우에는 배열의 두 번째면에 숨어 있습니다. 이 단계에서 어레이에 대해 알고있는 내용은 다음과 같습니다.

  • 왼쪽 = 0
  • 오른쪽 = 길이-1;
  • 중간 = 왼쪽 + (오른쪽-왼쪽) / 2;
  • arr [중간] = 2;
  • arr [왼쪽] = 2;
  • arr [오른쪽] = 2;
  • 목표 = 3;

이것이 우리가 가진 모든 정보입니다. 어레이의 절반을 제외하기로 결정하는 것만으로는 충분하지 않음을 분명히 알 수 있습니다. 그 결과, 유일한 방법은 선형 검색을 수행하는 것입니다. 나는 우리가 그 O (n) 시간을 최적화 할 수 없다고 말하는 것이 아니다. 내가 말하는 것은 우리가 O (log (n))을 할 수 없다는 것 뿐이다.


0

mid, mid-1 등으로 인해 바이너리 검색에 대해 마음에 들지 않는 것이 있기 때문에 항상 바이너리 스트라이드 / 점프 검색을 사용합니다.

회전 된 배열에서 사용하는 방법? 두 번 사용 (한 번 시프트를 찾은 다음 .at ()를 사용하여 시프트 된 인덱스-> 원래 인덱스를 찾습니다)

또는 첫 번째 요소를 비교합니다. 첫 번째 요소보다 작 으면 끝 근처에 있어야합니다.

끝에서 뒤로 점프 검색을 수행하고, 피벗 타이어 리 멘트가 발견되면 중지

> 시작 요소이면 일반 점프 검색을 수행하십시오. :)


0

C #을 사용하여 구현

public class Solution {
        public int Search(int[] nums, int target) {
             if (nums.Length == 0) return -1;
                int low = 0;
                int high = nums.Length - 1;
                while (low <= high)
                {
                    int mid = (low + high) / 2;
                    if (nums[mid] == target) return mid;
                    if (nums[low] <= nums[mid]) // 3 4 5 6 0 1 2
                    {
                        if (target >= nums[low] && target <= nums[mid])
                            high = mid;
                        else
                            low = mid + 1;
                    }
                    else // 5 6 0 1 2 3 4
                    {
                        if (target >= nums[mid] && target <= nums[high])
                            low= mid;
                        else
                            high = mid - 1;
                    }
                }
                return -1;
        }
    }

-1

반복되는 값으로 작동하는 또 다른 접근 방식은 회전을 찾은 다음 배열에 액세스 할 때마다 회전을 적용하는 정규 이진 검색을 수행하는 것입니다.

test = [3, 4, 5, 1, 2]
test1 = [2, 3, 2, 2, 2]

def find_rotated(col, num):
    pivot = find_pivot(col)
    return bin_search(col, 0, len(col), pivot, num)

def find_pivot(col):
    prev = col[-1]
    for n, curr in enumerate(col):
        if prev > curr:
            return n
        prev = curr
    raise Exception("Col does not seem like rotated array")

def rotate_index(col, pivot, position):
    return (pivot + position) % len(col)

def bin_search(col, low, high, pivot, num):
    if low > high:
        return None
    mid = (low + high) / 2
    rotated_mid = rotate_index(col, pivot, mid)
    val = col[rotated_mid]
    if (val == num):
        return rotated_mid
    elif (num > val):
        return bin_search(col, mid + 1, high, pivot, num)
    else:
        return bin_search(col, low, mid - 1,  pivot, num)

print(find_rotated(test, 2))
print(find_rotated(test, 4))
print(find_rotated(test1, 3))

-1

내 간단한 코드 :-

public int search(int[] nums, int target) {
    int l = 0;
    int r = nums.length-1;
    while(l<=r){
        int mid = (l+r)>>1;
        if(nums[mid]==target){
            return mid;
        }
        if(nums[mid]> nums[r]){
            if(target > nums[mid] || nums[r]>= target)l = mid+1;
            else r = mid-1;
        }
        else{
            if(target <= nums[r] && target > nums[mid]) l = mid+1;
            else r = mid -1;
        }
    }
    return -1;
}

시간 복잡도 O (log (N)).


-1

질문 : 회전 정렬 된 배열에서 검색

public class SearchingInARotatedSortedARRAY {
    public static void main(String[] args) {
        int[] a = { 4, 5, 6, 0, 1, 2, 3 };

        System.out.println(search1(a, 6));

    }

    private static int search1(int[] a, int target) {
        int start = 0;
        int last = a.length - 1;
        while (start + 1 < last) {
            int mid = start + (last - start) / 2;

            if (a[mid] == target)
                return mid;
            // if(a[start] < a[mid]) => Then this part of the array is not rotated
            if (a[start] < a[mid]) {
                if (a[start] <= target && target <= a[mid]) {
                    last = mid;
                } else {
                    start = mid;
                }
            }
            // this part of the array is rotated
            else {
                if (a[mid] <= target && target <= a[last]) {
                    start = mid;
                } else {
                    last = mid;
                }
            }
        } // while
        if (a[start] == target) {
            return start;
        }
        if (a[last] == target) {
            return last;
        }
        return -1;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.