CS/알고리즘_문제풀이(자바)

중복 없는 구간

Jedy_Kim 2021. 10. 3. 14:40
728x90

문제

n개의 숫자가 주어지고, 이 중에서 r개의 연속된 숫자를 선택했을 때, 이 연속 부분 내에는 숫자가 중복되지 않기를 원한다. 예를 들어, 다음과 같이 10개의 숫자에서 3개의 연속된 숫자를 선택할 수 있다.

이렇게 선택을 하면, 선택된 숫자들 사이에서는 중복이 존재하지 않는다. r의 최댓값을 구하는 프로그램을 작성하시오. 위의 경우, (4, 2, 1, 3)을 선택하면 되므로 r의 최댓값은 4이다. r이 5 이상이 될 경우, 중복 없이 연속 부분을 선택하는 것이 불가능하다.

 

입력

첫째 줄에는 숫자의 개수 n이 주어진다. ( 1 ≤ n ≤ 100,000 ) 둘째 줄에 n개의 숫자가 주어진다. 각 숫자는 항상 1보다 크거나 같고, n보다 작거나 같다.  

출력

r의 최댓값을 출력한다.

 

예제 입력

10

1 3 1 2 4 2 1 3 2 1

예제 출력

4

 

예제 입력

7

7 1 4 2 5 3 6

예제 출력

7

 

// 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import java.util.*;
import java.io.*;
 
public class Main{
  
  static int n;
  static int[] arr;
  static int[] arrCnt;
  static int start, end;
  static int maxSum = 0, maxIdx = 0;
  
  // 1. 초기의 누적합을 구해주는 메서드
  static boolean isDuplicate(int interval) {
    boolean flag = false;
    // 중복된 숫자의 개수를 카운팅한다.
    int cnt = 0;
    
    for(int i=0; i<interval; i++) {
      arrCnt[arr[i]] += 1;
      // 중복 됐냐 안됐냐만 판단하기 때문에
      // arrCnt의 값이 2를 넘는지 안넘는지만 체크한다.
      if(arrCnt[arr[i]] == 2) {
        cnt++;
      }
    }
    
    if(cnt == 0) flag = true;
    
    for(int i=0; i<n-interval; i++) {
      // 중복이였지만 -1을 하였을 때 중복이 아닌 경우 -1을 해준다.
      if(arrCnt[arr[i]] >= 2 && arrCnt[arr[i]] - 1 == 1) cnt--;
      arrCnt[arr[i]]   -= 1;
      arrCnt[arr[i+interval]] += 1;
      // arrCnt의 값이 중복이 되는 순간 +1해준다.
      if(arrCnt[arr[i+interval]] == 2) cnt++;
      
      if(cnt == 0) flag = true;
    }
     
    return flag;
  }
  
  
  public static void main(String[] args) throws Exception {
 
    // Please Enter Your Code Here
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    n      = Integer.parseInt(br.readLine());    
    arr    = new int[n];
    
    // 구간별 개별 숫자의 빈도수를 카운팅하는 배열을 만든다.
    // 반환 값이 true : 중복이 아니다, false : 해당 구간은 중복이다.
    int maxSize = -1;
    StringTokenizer st = new StringTokenizer(br.readLine());
    for(int i=0; i<n; i++) {
      arr[i] = Integer.parseInt(st.nextToken());
      if(maxSize < arr[i]) maxSize = arr[i];
    }
    
    
    // 구간의 시작점과 끝점
    start = 0;
    end   = n+1;
    
    int resInterval=1, resMax=0;
    
    while(start+1 < end) {
      arrCnt = new int[maxSize + 1];
      
      int mid = (start + end) / 2;
      boolean getFlag = isDuplicate(mid);
      
      // mid값을 넣었을 때 
      // 해당 구간이 중복이면 이후의 구간은 모두 중복이다.
      // 그래서 중복이 아니면 start값이 바뀌고
      // 중복이 아니면 end값이 바뀐다.
      if(getFlag) {
        start = mid;
        resInterval = mid;
      }
      else {
        end = mid;
      }
      
    }
    bw.write(String.valueOf(resInterval));
    
    br.close();
    bw.flush();
    bw.close();
  }
}
cs

 

반응형

'CS > 알고리즘_문제풀이(자바)' 카테고리의 다른 글

차이를 최대로  (0) 2021.10.04
모든 순열  (0) 2021.10.04
2차식 정답 추측  (0) 2021.10.03
나무 자르기  (0) 2021.10.02
NN단표  (0) 2021.10.02