• Feed
  • Explore
  • Ranking
/
/
    CodingTest

    코딩테스트 준비 F - 세워라 반석 위에

    혼자서 다시푸는 코딩테스트 준비 일지 - 78
    브루트포스투 포인터
    B
    Brocolling
    2024.12.11
    ·
    7 min read

    다시푸는 코딩 테스트 준비 일지

    • 응시 사이트 : BOJ

    • 문제 : 21967.세워라 반석위에

    • 사용언어 : C#

    • 난이도 : Middle

    • 풀이시간 : 1h 14m ++

    • 유형 : 브루트포스, 투 포인터

    문제

    드높은 남산 위에 우뚝 선

    (중략)

    세워라 반석 위에

    선린의 터를

    반석: 넓고 펀펀한 큰 돌, 너럭바위

    어떤 수열이 반석이라는 것은, 수열의 최댓값과 최솟값의 차이가 2 이하임을 의미한다.

    예를 들어 1 2 3 3 1 2는 최댓값(3)과 최솟값(1)의 차이가 2이므로 반석이고, 2 6 5 4는 최댓값(6)과 최솟값(2)의 차이가 4이므로 반석이 아니다.

    수열이 주어지면 수열의 연속한 부분 수열(부분 문자열, substring) 중, 가장 긴 반석의 길이를 구하는 프로그램을 작성하자.

    입력

    첫 번째 줄에 수열의 길이 NNN이 주어진다.

    두 번째 줄에는 수열 AAAA의 원소 A1,A2,⋯,AN
    A1,A2,⋯ ,ANA_1, A_2, \cdots , A_NA1​,A2​,⋯,AN​이 공백으로 구분되어 주어진다.

    출력

    수열 AAAA의 연속한 부분 수열 중 가장 긴 반석의 길이를 출력한다.

    제한

     1 ≤ N ≤ 1000000, 1≤N≤1 000 0001 \leq N \leq 1\,000\,0001≤N≤1000000 

     1 ≤ Ai ≤ 10, 1≤Ai≤101 \leq A_i \leq 101≤Ai​≤10 

    예제 입력 1 복사

    5
    1 2 1 3 1
    

    예제 출력 1 복사

    5
    

    예제 입력 2 복사

    7
    1 2 3 4 2 5 7
    

    예제 출력 2 복사

    4
    

    문제 풀이 접근

    문제 풀이는 2가지 방식으로 접근했다.
    1. Brute Force 방식
    2. 이분 탐색 방식

    Brute Force

    1. while(left <= right)를 사용하여 일반적인 투 포인터 알고리즘 구성
    2. int leftElement = arr[left] 로 기준으로 잡은 후에, for문을 arr.Length-1 까지 순회하여, 가장 긴 반석을 검색, 오른쪽도 동일하게 검색
    3. TC 통과, 시간 초과 판정
    4. 반복 조건 변경 left < (right/2)로 검색 가능할 것이라고 판단
    5. 시간 초과 판정, 알고리즘 변경

    이분 탐색

    1. logN의 시간 복잡도를 가진 이분 탐색이 적합하다고 판단.

    2. for문으로 arr.Length 까지 순회

    3. 현재 i 의 값 부터, 이분 탐색을 실행해, 현재 원소의 값+2 보다 큰 값을 찾는다.

    4. 탐색 시작한 left 값과 찾아낸 FindIndex 값을 연산하여 값 도출
      * 식 : FindIndex - left +1 ( 순열 갯수로 +1)

    5. 시간 복잡도 Pass, 값 Fail

    작성 코드 (C#) - 이분 탐색 실패

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Xml.Linq;
    using static CodingTestProj.Program;
    using System.Text;
    
    ///*
    // * Difficulty : Middle
    // * URL : https://www.acmicpc.net/problem/21967
    //  * Time : 1h 14m
    // */
    
    namespace CodingTestProj
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                Solution solu = new Solution();
                solu.solve();
            }
        }
    
        public class Solution
        {
            public int _n;
            public int[] _arr;
            public void solve()
            {
                _n = int.Parse(Console.ReadLine());
                _arr = new int[_n];
    
                string[] _in = Console.ReadLine().Split(' ');
    
                for (int i = 0; i < _in.Length; ++i)
                    _arr[i] = int.Parse(_in[i]);
    
                int _ret = int.MinValue;
                //Array.Sort(_arr); // 오름차순 정렬
    
                for (int i = 0; i < _arr.Length; ++i)
                {
                    int _val = _arr[i];
                    int _bsIdx = BinarySearch(_arr, i, _val);
    
                    if (_bsIdx >= _ret)
                        _ret = _bsIdx;
                }
    
                Console.WriteLine(_ret);
            }
    
            public int BinarySearch(int[] arr, int left, int val)
            {
                int sleft = left;
                int right = _arr.Length - 1;
    
                while (sleft < right)
                {
                    int mid = (sleft + right) / 2;
    
                    int min = Math.Min(val, arr[mid]);
                    int cur = Math.Max(val, arr[mid]);
    
                    if(min +2 <= cur)
                        right = mid;
                    else
                        sleft = mid + 1;
                }
    
                return sleft-left+1;
            }
        }
    }
    

    코드 결과

    * 코드 실패로 미 첨부







    - 컬렉션 아티클