J.Y.S
¿ whats my interest ?
J.Y.S
전체 방문자
오늘
어제
  • 분류 전체보기 (59)
    • 트러블슈팅 기록 (7)
    • Java&Kotlin (5)
    • Server (22)
    • 데이터 엔지니어링 (3)
    • Architecture& Design Patter.. (1)
    • Daily (11)
    • 알고리즘 공부 (9)

블로그 메뉴

  • 홈
  • 태그

공지사항

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
J.Y.S

¿ whats my interest ?

[C++/JAVA] 이진탐색 (lower bound) (2021카카오 - 순위검색)
알고리즘 공부

[C++/JAVA] 이진탐색 (lower bound) (2021카카오 - 순위검색)

2021. 11. 24. 02:47

이진 탐색이란?

정렬된 데이터에서 특정 값을 찾아내는 divide n conquer 알고리즘.

탐색이 반복될 때마다 탐색 구간이 1/2씩 감소한다. (bigO logn)

원리

1. 데이터 집합의 가운데 원소(mid)와 타겟(target)을 비교

2. mid > target 인 경우 집합의 왼쪽 1/2 부분 탐색하여 1 반복

3. mid < target 인 경우 집합의 오른쪽 1/2 부분 탐색하여 1 반복

1. C++ (성공 코드 포함)

코드

int binarySearch(int *arr, int arr_sz, int target) {
    int left = 0;
    int right = arr_sz - 1;
    while(left <= right) {
        int mid = (left + right) / 2;

        if (arr[mid] > target) {
            right = mid - 1;
        }
        else if (arr[mid] < target) {
            left = mid + 1;
        }
        else
            return mid;
    }
    return -1;
}

하지만 순위 검색 문제를 풀 때는 일치하지 않더라도 target보다 크거나 같은 데이터의 인덱스 값을 구해야했다. --> Lower bound (하한선) algorithm

Lower Bound Binary search

원리는 비슷하나,

target이 mid의 값과 같은 경우 return 하지 않고 해당 인덱스를 right(high)로 변경한 후 다시 이진 탐색을 진행한다.

int lowerBoundBinarySearch(int *arr, int arr_sz, int target) {
    int low = 0;
    int high = arr_sz;
    while(low < high) {
        int mid = (low + high) / 2;

        if (arr[mid] >= target) {
            high = mid;
        }
        else {
            low = mid + 1;
        }
    }
    return low;
}

메인 함수 포함 전체 코드

#include <iostream>

using namespace std;

int binarySearch(int *arr, int arr_sz, int target);
int lowerBoundBinarySearch(int *arr, int arr_sz, int target);
int main() {
    int array[10] = {1, 2, 2, 3, 3, 3, 4, 5, 7, 7};

    cout << "binary search for target 7" << endl;
    int ret = binarySearch(array, 10, 7);
    cout << ret << endl;
    cout << "binary search for target 6" << endl;
    cout << binarySearch(array, 10, 6) << endl;
    cout << "==========================" << endl;
    cout << "lower bound binary search for target 7" << endl;
    cout << lowerBoundBinarySearch(array, 10, 7)<< endl;
    cout << "lower bound binary search for target 6" << endl;
    cout << lowerBoundBinarySearch(array, 10, 6) << endl;
}

int binarySearch(int *arr, int arr_sz, int target) {
    int left = 0;
    int right = arr_sz - 1;
    while(left <= right) {
        int mid = (left + right) / 2;

        if (arr[mid] > target) {
            right = mid - 1;
        }
        else if (arr[mid] < target) {
            left = mid + 1;
        }
        else
            return mid;
    }
    return -1;
}

int lowerBoundBinarySearch(int *arr, int arr_sz, int target) {
    int low = 0;
    int high = arr_sz;
    while(low < high) {
        int mid = (low + high) / 2;

        if (arr[mid] >= target) {
            high = mid;
        }
        else {
            low = mid + 1;
        }
    }
    return low;
}

배열 { 1, 2, 2, 3, 3, 3, 4, 5, 7, 7 } 에 대한 이진 탐색 결과:

2. JAVA(효율 0 --> 문제 해결 O)

구현한 로직:

  • info에 대해 '-'를 추가한 모든 경우의 수를 만들어 해쉬테이블에 넣는다.
  • query를 불러와 데이터를 파싱한 후 해쉬테이블에 key로써 접근하여 score데이터를 가져온다.
  • score데이터를 이진탐색을 사용하여 기준이상의 데이터의 개수를 센다.(lower bound 사용)
  • 순서대로 값을 반환한다.

했는데도 효율성 0

이었던 이유는..

LinkedList 에 점수를 저장해서이다. ArrayList 로 바꾸니 해결되었다.

문제의 코드:

더보기
import java.util.LinkedList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Collections;

class Solution {
    static HashMap<String, List<Integer>> m = new HashMap<>();

    static int binarySearch(int score, String str) {
        int ret = 0;
        List<Integer> values = m.get(str);
        int size = values.size();
        int right = size - 1;
        int left = 0;
        int mid = 0;
        while(left <= right) {
            mid = (right + left) / 2;
            if (score <= values.get(mid)) { // score <= values.get(mid)
                right = mid - 1;
            }
            else { // score > values.get(mid)
                left = mid + 1;
            }
        }
        return size - left;
    }

    void dfs(String[] token, int lv, String str) {

        if (lv == 4) {
            if (m.containsKey(str)) {
                m.get(str).add(Integer.parseInt(token[4]));
            }
            else {
                List<Integer> list = new LinkedList<>();
                list.add(Integer.parseInt(token[4]));
                m.put(str, list);
            }
            return;
        }

        dfs(token, lv+1,str.concat(token[lv]));
        dfs(token, lv+1, str.concat("-"));
    }

    public int[] solution(String[] info, String[] query) {
        int qSize = query.length;
        int[] answer = new int[qSize];

        for (String str: info) {
            String[] token = str.split("\\s");

            List<String> keys = new LinkedList<>();
            dfs(token, 0, "");
        }

        int i=-1;
        HashSet<String> sorted = new HashSet<>();
        for (String quer: query) {
            i++;
            quer = quer.replace(" and ", "");
            String[] token = quer.split("\\s");

            int score = Integer.parseInt(token[1]);
            String m_key = token[0];
            List<Integer> values = m.get(m_key);
            if (values == null) {
                answer[i] = 0;
                continue;
            }

            if (!sorted.contains(m_key)) {
                Collections.sort(values);
                sorted.add(m_key);
            }

            answer[i] = binarySearch(score, m_key);
        }
        return answer;
    }
}

해결 후 : 

LinkedList -> ArrayList

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Collections;

class Solution {
    static HashMap<String, List<Integer>> m = new HashMap<>();

    // answer[i] = binarySearch(0, values.size(), score, values);
    static int binarySearch(int score, String str) {
        int ret = 0;
        List<Integer> values = m.get(str);
        int size = values.size();
        int right = size - 1;
        int left = 0;
        int mid = 0;
        while(left <= right) {
            mid = (right + left) / 2;
            if (score <= values.get(mid)) { // score <= values.get(mid)
                right = mid - 1;
            }
            else { // score > values.get(mid)
                left = mid + 1;
            }
        }
        return size - left;
    }

    void dfs(String[] token, int lv, String str) {

        if (lv == 4) {
            if (m.containsKey(str)) {
                m.get(str).add(Integer.parseInt(token[4]));
            }
            else {
                List<Integer> list = new ArrayList<>();
                list.add(Integer.parseInt(token[4]));
                m.put(str, list);
            }
            return;
        }

        dfs(token, lv+1,str.concat(token[lv]));
        dfs(token, lv+1, str.concat("-"));
    }

    public int[] solution(String[] info, String[] query) {
        int qSize = query.length;
        int[] answer = new int[qSize];

        for (String str: info) {
            String[] token = str.split("\\s");

            List<String> keys = new ArrayList<>();
            dfs(token, 0, "");
        }

        int i=-1;
        HashSet<String> sorted = new HashSet<>();
        for (String quer: query) {
            i++;
            quer = quer.replace(" and ", "");
            String[] token = quer.split("\\s");

            int score = Integer.parseInt(token[1]);
            String m_key = token[0];
            List<Integer> values = m.get(m_key);
            if (values == null) {
                answer[i] = 0;
                continue;
            }

            if (!sorted.contains(m_key)) {
                Collections.sort(values);
                sorted.add(m_key);
            }

            answer[i] = binarySearch(score, m_key);
        }
        return answer;
    }
}
저작자표시 (새창열림)

'알고리즘 공부' 카테고리의 다른 글

누적합 알고리즘 (2022 카카오 - 파괴되지 않은 건물)  (0) 2022.09.07
백준에서 C++ 로 풀 때 시간초과 나는 경우  (0) 2021.10.01
Leet code 가입  (0) 2021.09.16
[C++] vector 클래스 - 2차원 벡터 초기화  (0) 2021.07.01
프로그래머스(#60057)-문자열 압축 (C++)  (0) 2021.06.30
    '알고리즘 공부' 카테고리의 다른 글
    • 누적합 알고리즘 (2022 카카오 - 파괴되지 않은 건물)
    • 백준에서 C++ 로 풀 때 시간초과 나는 경우
    • Leet code 가입
    • [C++] vector 클래스 - 2차원 벡터 초기화
    J.Y.S
    J.Y.S

    티스토리툴바