카테고리 없음

[백준/JAVA] 1517번: 버블 소트

imname1am 2023. 4. 14. 13:38
반응형

🔺 문제

 

1517번: 버블 소트

첫째 줄에 N(1 ≤ N ≤ 500,000)이 주어진다. 다음 줄에는 N개의 정수로 A[1], A[2], …, A[N]이 주어진다. 각각의 A[i]는 0 ≤ |A[i]| ≤ 1,000,000,000의 범위에 들어있다.

www.acmicpc.net

스윗 럽 스윗 드림~ 버블버블~

 

 

🔺 코드

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
import java.util.*;
import java.io.*;
 
public class Main {
    static long[] A, tmp;
    static long result;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int N = Integer.parseInt(br.readLine());
        A = new long[N + 1];
        tmp = new long[N + 1];
        
        StringTokenizer st = new StringTokenizer(br.readLine()," ");
        for(int i = 1 ; i <= N ; i++) {
            A[i] = Integer.parseInt(st.nextToken());
        }
        
        result = 0;
        merge_sort(1, N);   // 병합 정렬
        
        System.out.println(result);
    }
    
    public static void merge_sort(int s, int e) {
        if(e - s < 1)
            return;
       
        int mid = s + (e - s) / 2;
        merge_sort(s, mid);
        merge_sort(mid + 1 , e);
        
        // tmp 배열 저장
        for(int i = s ; i <= e ; i++) {
            tmp[i] = A[i];
        }
        
        // 두 그룹 병합
        int tmpIdx = s; // 현재 복사 위치
        int idx1 = s;
        int idx2 = mid + 1;
        
        while(idx1 <= mid && idx2 <= e) {
            if(tmp[idx1] > tmp[idx2]) { // 뒤쪽 데이터 값이 작은 경우 업데이트
                A[tmpIdx] = tmp[idx2];
                result += idx2 - tmpIdx; // 🔔 업데이트
                tmpIdx++;
                idx2++;
            }
            else {
                A[tmpIdx++= tmp[idx1++];
            }
        }
        
        // 부분이 남은 경우
        while(idx1 <= mid) {
            A[tmpIdx++= tmp[idx1++];
        }
        while(idx2 <= e) {
            A[tmpIdx++= tmp[idx2++];
        }
    }
}
cs
✅ 해결 아이디어
- O(nlogn)의 시간 복잡도로 정렬 수행
- 병합 정렬 : 분할 → 정렬 → 합병. 

 

💥 유의사항

두 그룹 병합하는 로직의 첫 번째 while문 안의 if문에서 tmp[idx1] > tmp[mid]이 먼저 나와야한다....

별 생각 없이 두개 순서 바꿔서 작성해봤었는데 안 그러면 67%에서 자꾸 틀림,,,,

 

사유는 아래와 같음,,

 


🔺 다른 풀이들

- 정렬 메소드와 합병 메소드를 따로 두심.

 

백준 1517번. 버블 소트 (Java)

문제 링크 : https://www.acmicpc.net/problem/1517 문제 이름은 버블소트지만 버블소트로 풀면 틀리는 문제입니다. N이 최대 500,000 이죠 O(n^2)을 돌리면 당연하게도 시간초과가 납니다. 우리가 구해야 하는

bcp0109.tistory.com

 

 

- 복습용..

 

백준 1517번: 버블 소트 [분할정복][재귀] - Java

www.acmicpc.net/problem/1517 1517번: 버블 소트 첫째 줄에 N(1≤N≤500,000)이 주어진다. 다음 줄에는 N개의 정수로 A[1], A[2], …, A[N]이 주어진다. 각각의 A[i]는 0≤|A[i]|≤1,000,000,000의 범위에 들어있다. www.acmi

cceeun.tistory.com

 

 

 

- 신기방기...

 

[백준 1517] 버블 소트 (JAVA)

https://www.acmicpc.net/problem/1517버블 정렬을 이용하면 N^2으로 시간초과가 발생합니다. 병합 정렬을 이용하여 해결할 수 있습니다.병합 정렬을 진행하면서 두 개의 배열을 병합할 때 Swap 횟수를 계산

velog.io


💬 느낀 점

병합 정렬,,,,, 마스터하고 말거다...

 

1회독 2회독 3회독 4회독 5회독
V 6/14      

 

 

( + 6/14 2회독)

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
import java.util.*;
import java.io.*;
 
public class Main {
    static long[] A, tmp;
    static long cnt;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int N = Integer.parseInt(br.readLine());
        A  = new long[N + 1];
        tmp  = new long[N + 1]; // 임시 저장 배열
        
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        for(int i = 1 ; i <= N ; i++) {
            A[i] = Long.parseLong(st.nextToken());
        }
        
        cnt = 0;
        merge_sort(1, N);
        System.out.println(cnt);
    }
    
    // 1. 분할
    private static void merge_sort(int s, int e) {
        if(s < e) {
            int mid = s + (e - s) / 2;
            merge_sort(s, mid);
            merge_sort(mid + 1, e);
            merge(s, mid, e);
        }
    }
    
    // 2. 정복
    private static void merge(int s, int m, int e) {
        // 정렬이 필요한 배열을 필요한 만큼 "매번" 복사
        for(int i = s ; i <= e ; i++) {
            tmp[i] = A[i];
        }
        
        // 두 그룹 병합 로직
        int l = s;
        int r = m + 1;
        int idx = s;    // 현재 복사 위치
        
        while(l <= m && r <= e) {
            if(tmp[l] <= tmp[r]) {
                A[idx] = tmp[l];
                l++;
            } else {    // 뒤쪽 데이터 값이 작은 경우 swap 발생했으므로 cnt 업데이트
                A[idx] = tmp[r];
                cnt += (m + 1 - l);     // 🔔 앞쪽 배열의 남은 데이터 개수만큼 더함
                r++;
            }
            idx++;
        }
        
        // 앞쪽 배열에 데이터 남아있는 경우, 배열 끝에서 남은만큼을 돌면서 값 채우기
        // (뒷 부분에 남은 거는 상관 없음)
        while(l <= m) {
            A[idx++= tmp[l++];
        }
       // while(r <= e) {
       //     A[idx++] = tmp[r++];
       // }
    }
}
cs

두 번째 본다고 좀 알 것 같다..만

혼자서 구현은 못 했다. (분발하자!!!)

 

암튼 이번에 풀면서 느꼈던 점 및 유의사항은 아래와 같다...

 

 

1) 28번째 줄 int mid = s + (e - s) / 2; 를  int mid = (s + e) / 2;로 써도 된다.

 

2) 정렬이 필요한 배열은 "매번" 복사해야 한다.

 

3) 48번째 줄 if(tmp[l] <= tmp[r]) ☞ 등호 빠뜨리면 틀리더라...

 

4) 52-54번째 줄 : 순서를 조심해야 한다. A[idx++] = tmp[r++] 하고 cnt 업데이트 하면 틀린다.

순서가 반드시 1) 현재 idx와 r을 이용해 cnt 세기 → 2) 갯수 ++ 어야 한다.

 

5) 53번째 줄 : cnt += (m + 1 - l);를 cnt += r - idx;  로 해도 된다. 원소가 앞으로 이동한 거리만큼 result에 더하는 것..

 

 


(참고)

 

✔ 병합 정렬 문제

 

[백준/JAVA] 24060번: 알고리즘 수업 - 병합 정렬 1

🔺 문제 24060번: 알고리즘 수업 - 병합 정렬 1 첫째 줄에 배열 A의 크기 N(5 ≤ N ≤ 500,000), 저장 횟수 K(1 ≤ K ≤ 108)가 주어진다. 다음 줄에 서로 다른 배열 A의 원소 A1, A2, ..., AN이 주어진다. (1 ≤ Ai

bono039.tistory.com

 

[백준/JAVA] 2751번: 수 정렬하기 2

🔺 문제 2751번: 수 정렬하기 2 첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지

bono039.tistory.com

 

반응형