Skip to main content

31. [Java] 배열만들기 3

https://school.programmers.co.kr/learn/courses/30/lessons/181895

  • 정수 배열 arr와 2개의 구간이 담긴 배열 intervals가 주어진다.
  • intervals는 항상 [[a1, b1], [a2, b2]]의 꼴로 주어지며 각 구간은 닫힌 구간이다.
  • 닫힌 구간 양 끝값과 그 사이의 값을 모두 포함하는 구간을 의미한다.

이때 배열 arr의 첫 번째 구간에 해당하는 배열과 두 번째 구간에 해당하는 배열을 앞뒤로 붙여 새로운 배열을 만들어 return 하는 solution 함수를 완성해 주세요.


  • 1 ≤ arr의 길이 ≤ 100,000
    • 1 ≤ arr의 원소 < 100
  • 1 ≤ a1 ≤ b1 < arr의 길이
  • 1 ≤ a2 ≤ b2 < arr의 길이

정답코드

import java.util.Arrays;

class Solution {
    public int[] solution(int[] arr, int[][] intervals) {
        int[] part1 = Arrays.copyOfRange(arr, intervals[0][0], intervals[0][1] + 1);
        int[] part2 = Arrays.copyOfRange(arr, intervals[1][0], intervals[1][1] + 1);
        
        // 두 배열을 합치기
        int[] answer = new int[part1.length + part2.length];
        System.arraycopy(part1, 0, answer, 0, part1.length);
        System.arraycopy(part2, 0, answer, part1.length, part2.length);
        
        return answer;
    }
}
Arrays.copyOfRange()

Arrays.copyOfRange() 메서드는 자바에서 배열의 일부 구간을 잘라서 새 배열로 만드는 간단한 방법이다.

Arrays.copyOfRange(originalArray, fromIndex, toIndex);
Arrays.copyOfRange(원본배열, 시작인덱스, 끝인덱스);
  • 시작인덱스: 포함됨 (inclusive)
  • 끝인덱스: 포함되지 않음 (exclusive) → 즉, 마지막 인덱스 + 1 해야 끝까지 포함됨
int[] arr = {10, 20, 30, 40, 50};

int[] sub = Arrays.copyOfRange(arr, 1, 4);  // 인덱스 1~3까지 복사
System.out.println(Arrays.toString(sub));  // [20, 30, 40]
  • 끝 인덱스를 배열 범위를 초과해서 넣으면 ArrayIndexOutOfBoundsException발생하지 않고, 자동으로 null 또는 0으로 채운 배열이 나온다 (단, 시작 인덱스는 범위 안이어야 함).
  • 따라서 정확한 인덱스를 계산하려면 끝 - 시작 + 1 범위를 쓰는 경우라면 끝 + 1을 넣어야 한다.


코드 예시

설명

arr[2] 부터 arr[4] 까지 복사

Arrays.copyOfRange(arr, 2, 5)

끝 인덱스는 포함 안 되므로 5까지

전체 복사

Arrays.copyOfRange(arr, 0, arr.length)

전부 복사 가능

길이 구간 계산 필요

end - start + 1

실제 개수 계산 시 사용


System.arraycopy() 메서드

배열에서 배열로 데이터를 빠르게 복사해주는 자바의 내장 메서드

System.arraycopy(sourceArray, sourceStartPos, destinationArray, destStartPos, length);
System.arraycopy(원본배열, 원본시작위치, 대상배열, 대상시작위치, 복사할개수);
  • 원본배열: 데이터를 복사할 출발지 배열
  • 원본시작위치: 출발지 배열에서 복사를 시작할 인덱스
  • 대상배열: 데이터를 복사할 목적지 배열
  • 대상시작위치: 목적지 배열에서 붙여넣기 시작할 인덱스
  • 복사할개수: 복사할 원소 수
System.arraycopy(part1, 0, answer, 0, part1.length);
  • part1 배열의 처음부터(part1[0])
  • part1.length 만큼을
  • answer 배열의 처음부터(answer[0]) 복사함
System.arraycopy(part2, 0, answer, part1.length, part2.length);
  • part2 배열의 처음부터(part2[0])
  • part2.length 만큼을
  • answer 배열의 part1.length 위치부터 이어서 복사함

즉, part1part2를 차례대로 answer 배열에 붙이는 로직이다.

Array()와 반복문을 사용해서 해결한 코드

import java.util.*;

class Solution {
    public int[] solution(int[] arr, int[][] intervals) {
        int start1 = intervals[0][0];
        int end1 = intervals[0][1];
        int start2 = intervals[1][0];
        int end2 = intervals[1][1];
        
        // 각각의 구간 길이 계산 (+1 필요)
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        
        int[] answer = new int[len1 + len2];
        int idx = 0;
        
        // 첫 번째 구간 복사
        for (int i = start1; i <= end1; i++) {
            answer[idx++] = arr[i];
        }
        // 두 번째 구간 복사
        for (int i = start2; i <= end2; i++) {
            answer[idx++] = arr[i];
        }
        
        return answer;
    }
}
  1. 두 구간의 시작점과 끝점을 가져온다
    • intervals 배열에 주어진 두 구간의 시작 인덱스(start1, start2)와 끝 인덱스(end1, end2)를 각각 변수에 저장한다.
  2. 각 구간의 길이를 계산하고, 결과를 담을 배열을 만든다
    • 두 구간의 길이를 각각 계산해서(end - start + 1), 전체 길이에 맞는 answer 배열을 생성한다.
  3. 첫 번째 구간의 값을 복사하여 answer 배열에 저장한다
    • arr[start1]부터 arr[end1]까지 반복하며 answer 배열에 차례대로 복사한다.
  4. 두 번째 구간의 값을 이어서 answer 배열에 저장한다
    • arr[start2]부터 arr[end2]까지 반복하며 answer 배열의 뒤에 이어서 복사한다.

오답

class Solution {
    public int[] solution(int[] arr, int[][] intervals) {
        int first = intervals[0][1] - intervals[0][0];
        int last = intervals[1][1] - intervals[1][0];
        int[] answer = new int[first + last];
        
        for (int i = 0; i < first; i++) {
            answer[i] = arr[i];
        }
        for (int i = first; i < last; i++) {
            answer[i] = arr[i];
        }
        return answer;
    }
}

image.png

1. firstlast 계산이 틀림

int first = intervals[0][1] - intervals[0][0];
int last = intervals[1][0] - intervals[1][0];
  • first첫 번째 구간의 길이인데 +1이 빠졌다. 예: [1, 3]이면 3 - 1 + 1 = 3개가 되어야 한다.
  • last도 마찬가지이다.

2. arr에서 복사할 때 인덱스를 잘못 사용함

for (int i = 0; i < first; i++) {
    answer[i] = arr[i];
}
  • 이건 0번 인덱스부터 first 개를 가져오는데, 문제는 intervals[0][0]부터 시작해야 한다.
  • 예를 들어 arr = {1,2,3,4,5}, intervals[0] = {1,3}이면 2,3,4를 가져와야 하는데 내가 쓴 코드는 1,2,3을 가져온다.
int start = intervals[0][0];
int end = intervals[0][1];
int index = 0;

for (int i = start; i <= end; i++) {
    answer[index++] = arr[i];
}
  • 이렇게 start와 end를 따로 빼서 인덱스를 계산하는 것이 올바른 결과를 낸다.

3. 두 번째 for문은 무조건 틀림

for (int i = first; i < last; i++) {
    answer[i] = arr[i];
}
  • i = first부터 i < last 조건인데, last == 0이기 때문에 이 루프는 아예 실행되지 않음
  • arr[i]에서 어떤 구간도 지정하지 않고 그냥 i를 쓰고 있음
int start2 = intervals[1][0];
int end2 = intervals[1][1];
int index = firstLength; // 첫 구간 길이 이후부터 채움

for (int i = start2; i <= end2; i++) {
    answer[index++] = arr[i];
}
  • 두 번째 구간의 시작/끝 인덱스를 따로 구하고 answer 배열에 이어서 넣어야 한다.