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을 넣어야 한다.
코드 예시 | 설명 | |
---|---|---|
|
| 끝 인덱스는 포함 안 되므로 5까지 |
전체 복사 |
| 전부 복사 가능 |
길이 구간 계산 필요 |
| 실제 개수 계산 시 사용 |
✅ 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 위치부터 이어서 복사함
즉, part1
과 part2
를 차례대로 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;
}
}
- 두 구간의 시작점과 끝점을 가져온다
intervals
배열에 주어진 두 구간의 시작 인덱스(start1
,start2
)와 끝 인덱스(end1
,end2
)를 각각 변수에 저장한다.
- 각 구간의 길이를 계산하고, 결과를 담을 배열을 만든다
- 두 구간의 길이를 각각 계산해서(
end - start + 1
), 전체 길이에 맞는answer
배열을 생성한다.
- 두 구간의 길이를 각각 계산해서(
- 첫 번째 구간의 값을 복사하여 answer 배열에 저장한다
arr[start1]
부터arr[end1]
까지 반복하며answer
배열에 차례대로 복사한다.
- 두 번째 구간의 값을 이어서 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;
}
}
1. first
와 last
계산이 틀림
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 배열에 이어서 넣어야 한다.