배열의 마지막 두 원소에 따라 값을 추가하는 알고리즘 문제 풀이 (Java)
이번 글에서는 배열의 마지막 두 원소를 비교하여 값을 추가하는 간단한 알고리즘 문제를 Java로 풀어보겠습니다. 문제는 배열의 마지막 원소와 그 이전 원소를 비교한 결과에 따라 배열에 새로운 값을 추가하는 방식으로 해결됩니다. 이 과정에서 다양한 배열 복사 및 확장 방법도 함께 알아보겠습니다. 이 글을 통해 배열을 효율적으로 확장하고 복사하는 여러 가지 방법에 대해 이해하고, 각 방법의 장단점을 파악하여 적절하게 사용할 수 있도록 해보겠습니다. 이 글이 여러분이 배열을 더 깊이 이해하고, Java를 통해 효율적으로 배열을 다루는 방법을 배우는 데 도움이 되기를 바랍니다.
문제 설명
정수 리스트 num_list
가 주어질 때, 마지막 원소가 그 전 원소보다 크다면 마지막 원소에서 그 전 원소를 뺀 값을 배열에 추가하고, 그렇지 않다면 마지막 원소의 두 배 값을 추가합니다. 이 조건을 만족하도록 solution
함수를 구현해야 합니다. 이 문제는 간단해 보이지만, 배열을 확장하고 복사하는 여러 방법을 학습할 수 있는 좋은 기회가 됩니다. 특히 배열의 크기를 동적으로 관리하는 여러 가지 기술을 다루는 데 있어서, 실제로 배열의 크기를 변경하는 다양한 방식들을 이해하는 데 큰 도움이 될 것입니다.
제한사항
num_list
의 길이는 최소 2에서 최대 10까지입니다.- 각 원소는 1 이상 9 이하의 정수입니다.
입출력 예
num_list | 결과 |
---|---|
[2, 1, 6] | [2, 1, 6, 5] |
[5, 2, 1, 7, 5] | [5, 2, 1, 7, 5, 10] |
입출력 예 #1: 마지막 원소 6
이 그 전 원소 1
보다 크므로 6 - 1 = 5
를 추가합니다.
입출력 예 #2: 마지막 원소 5
가 그 전 원소 7
보다 크지 않으므로 5 * 2 = 10
을 추가합니다. 이와 같은 방식으로 배열의 마지막 두 원소를 비교하여 조건에 맞게 새로운 값을 추가하는 것이 목표입니다. 이를 통해 조건문과 배열 연산을 결합하여 문제를 해결하는 과정을 학습할 수 있습니다.
해결 방법
배열을 확장하고 새로운 값을 추가해야 하므로, 배열 복사 및 확장을 위한 다양한 방법을 활용할 수 있습니다. 이 문제를 해결하면서 배열을 확장하는 여러 방법에 대해 알아보겠습니다. 각 방법마다 코드 예시와 함께, 장단점 및 사용 상황에 대한 설명을 제공하겠습니다. 자바에서 배열은 크기가 고정되어 있어 배열의 크기를 동적으로 변경하려면 새로운 배열을 생성해야 합니다. 이러한 특성을 고려하여 배열을 동적으로 다루기 위한 다양한 기술을 이해해 보겠습니다.
기존 풀이 코드
class Solution {
public int[] solution(int[] num_list) {
int[] answers = new int[num_list.length + 1];
for (int i = 0; i < num_list.length; i++) {
answers[i] = num_list[i];
}
int lastValue = num_list[num_list.length - 1];
int lastBeforeValue = num_list[num_list.length - 2];
answers[answers.length - 1] = (lastValue > lastBeforeValue) ? lastValue - lastBeforeValue : lastValue * 2;
return answers;
}
}
시간 복잡도
위 코드의 시간 복잡도는 O(n)입니다. n
은 num_list
의 길이를 나타내며, for 루프를 통해 배열의 모든 원소를 복사하는 과정에서 n
번의 반복이 필요합니다. 배열의 길이가 최대 10이므로, 이 반복의 비용은 매우 작고 효율적이라고 할 수 있습니다. 배열이 더 크다면 성능 문제가 될 수 있겠지만, 이 문제의 제한 사항 내에서는 매우 적절한 해결 방법입니다. 배열을 순차적으로 탐색하면서 새로운 배열에 값을 복사하는 방식이므로 시간 복잡도는 입력 배열의 크기에 비례하게 됩니다.
공간 복잡도
공간 복잡도는 O(n)입니다. 새로운 배열 answers
를 생성하여 기존 배열보다 한 칸 더 큰 크기를 갖게 됩니다. 이 추가된 공간이 필요하기 때문에 공간 복잡도는 입력 배열의 크기와 비례하게 됩니다. 따라서 num_list
의 길이가 n
이라면, 새로운 배열의 공간 요구량도 n + 1
입니다. 새로운 배열을 만들고 기존 데이터를 모두 복사하는 방식이기 때문에, 이는 추가적인 메모리 공간을 필요로 하며, 메모리 사용량이 늘어나는 방식입니다.
이 코드에서는 기존 배열을 확장하여 마지막 원소를 추가하는 방식으로 배열을 처리하고 있습니다. 다음으로, 배열을 복사하고 확장하는 여러 방법을 자세히 살펴보겠습니다. 배열의 크기를 늘리는 여러 가지 접근 방식을 통해 코드의 효율성을 높일 수 있는 방법을 배워봅시다. 배열 확장은 배열의 재할당이 필요한 경우가 많기 때문에, 이러한 상황에서 효율적으로 작업하는 방법을 이해하는 것이 중요합니다.
1. Arrays.copyOf()
를 사용하는 방식
Arrays.copyOf()
는 자바에서 배열을 복사하고, 새 크기로 배열을 확장하는 가장 간단한 방법 중 하나입니다. 기존 배열의 내용을 복사하고, 배열의 길이를 원하는 만큼 늘리며, 늘어난 부분은 기본값으로 채워집니다.
사용 방법:
import java.util.Arrays;
class Solution {
public int[] solution(int[] num_list) {
int lastValue = num_list[num_list.length - 1];
int lastBeforeValue = num_list[num_list.length - 2];
int newValue = (lastValue > lastBeforeValue) ? lastValue - lastBeforeValue : lastValue * 2;
// Arrays.copyOf로 배열을 복사하고 크기를 확장
int[] result = Arrays.copyOf(num_list, num_list.length + 1);
result[result.length - 1] = newValue; // 마지막에 새로운 값 추가
return result;
}
}
이 방법은 배열을 확장하는 가장 직관적인 방식으로, 코드가 간결하고 이해하기 쉽습니다. 배열의 크기를 고정적으로 늘리며, 확장된 부분은 기본값(0)으로 채워지기 때문에 간단한 문제를 해결하는 데 적합합니다. 특히 크기가 크지 않은 배열에서 유용하며, 배열 복사와 확장을 한 번에 처리할 수 있어 간단한 문제 해결 시 효과적입니다. 그러나 배열 크기가 매우 큰 경우, 새로운 배열 할당과 복사가 성능에 영향을 줄 수 있습니다.
2. System.arraycopy()
를 사용하는 방식
System.arraycopy()
는 자바의 기본 배열 복사 메서드로, 매우 빠르고 효율적으로 배열을 복사할 수 있는 메서드입니다. 이 방법은 배열의 특정 부분을 복사하고자 할 때 매우 유용하며, 성능 측면에서 매우 효율적입니다.
사용 방법:
class Solution {
public int[] solution(int[] num_list) {
int lastValue = num_list[num_list.length - 1];
int lastBeforeValue = num_list[num_list.length - 2];
int newValue = (lastValue > lastBeforeValue) ? lastValue - lastBeforeValue : lastValue * 2;
int[] result = new int[num_list.length + 1];
System.arraycopy(num_list, 0, result, 0, num_list.length);
result[result.length - 1] = newValue;
return result;
}
}
System.arraycopy()
는 배열을 복사하는 고성능 방법으로, 대용량 데이터 처리 시에도 유리합니다. 배열의 시작 위치와 복사할 길이를 지정할 수 있어 세밀한 제어가 가능하며, 높은 성능이 요구되는 상황에서 적합합니다. 이 메서드는 Java의 네이티브 메서드로 구현되어 있어 직접 루프를 사용하여 복사하는 것보다 더 빠릅니다. 배열의 길이가 길어질수록 성능 차이는 더 크게 나타날 수 있습니다. 따라서 고성능이 중요한 프로젝트에서는 이 방법을 선택하는 것이 좋습니다.
3. List<Integer>
로 변환 후 배열로 변환하는 방식
자바에서 배열의 크기는 고정되어 있기 때문에, 배열을 동적으로 확장하거나 줄이기 위해 List
를 사용할 수 있습니다. 이 방법은 배열의 유연성을 높이고, 배열에 요소를 동적으로 추가하거나 제거하는 데 적합합니다.
사용 방법:
import java.util.ArrayList;
import java.util.List;
class Solution {
public int[] solution(int[] num_list) {
int lastValue = num_list[num_list.length - 1];
int lastBeforeValue = num_list[num_list.length - 2];
int newValue = (lastValue > lastBeforeValue) ? lastValue - lastBeforeValue : lastValue * 2;
List<Integer> list = new ArrayList<>();
for (int num : num_list) {
list.add(num);
}
list.add(newValue);
return list.stream().mapToInt(i -> i).toArray();
}
}
이 방법은 배열을 List
로 변환하여 크기 변경의 유연성을 제공합니다. 새로운 요소를 쉽게 추가할 수 있으며, 마지막에 리스트를 다시 배열로 변환하여 반환합니다. 다만, List
와 배열 간의 변환 과정에서 약간의 성능 오버헤드가 발생할 수 있습니다. 이 방법은 코드가 직관적이고 동적 크기 조정이 필요할 때 유용하지만, 메모리 사용 측면에서 비효율적일 수 있습니다. 특히, 리스트를 배열로 다시 변환하는 과정에서 추가적인 메모리와 시간이 소모되기 때문에, 큰 데이터셋에 대해서는 신중하게 사용하는 것이 좋습니다.
4. Streams
를 사용한 방식
자바 8 이상에서는 Stream API
를 이용해 배열을 쉽게 처리할 수 있습니다. 스트림을 사용하면 더 함수형 프로그래밍 스타일로 배열을 다룰 수 있어 코드가 간결하고 읽기 쉬워집니다.
사용 방법:
import java.util.stream.IntStream;
class Solution {
public int[] solution(int[] num_list) {
int lastValue = num_list[num_list.length - 1];
int lastBeforeValue = num_list[num_list.length - 2];
int newValue = (lastValue > lastBeforeValue) ? lastValue - lastBeforeValue : lastValue * 2;
return IntStream.concat(IntStream.of(num_list), IntStream.of(newValue)).toArray();
}
}
스트림을 사용하면 배열을 더 쉽게 다룰 수 있으며, 특히 함수형 스타일로 데이터를 처리하는 것이 가능해집니다. 코드가 간결해지지만, 작은 배열에서는 성능 오버헤드가 발생할 수 있어 적절한 상황에서 사용하는 것이 좋습니다. 함수형 프로그래밍을 선호하거나, 코드의 간결성을 중시하는 경우 이 방법을 사용하는 것이 좋습니다. 하지만 스트림은 내부적으로 반복자를 사용하므로, 큰 배열을 처리할 때는 성능이 떨어질 수 있습니다. 따라서 성능과 메모리 효율이 중요한 경우에는 다른 방법을 고려해야 합니다.
5. Arrays.copyOfRange()
를 사용하는 방식
Arrays.copyOfRange()
는 배열의 특정 범위를 복사하는 메서드로, 범위 내의 배열을 쉽게 복사하고 확장할 수 있습니다. 이 방법은 배열의 일부만 복사하거나, 배열을 확장하는 데 유리합니다.
사용 방법:
import java.util.Arrays;
class Solution {
public int[] solution(int[] num_list) {
int lastValue = num_list[num_list.length - 1];
int lastBeforeValue = num_list[num_list.length - 2];
int newValue = (lastValue > lastBeforeValue) ? lastValue - lastBeforeValue : lastValue * 2;
int[] result = Arrays.copyOfRange(num_list, 0, num_list.length + 1);
result[result.length - 1] = newValue;
return result;
}
}
이 방법은 배열의 특정 범위를 복사하여 새로운 배열을 생성할 때 유용합니다. Arrays.copyOf()
와 비슷하지만, 시작과 끝 인덱스를 지정할 수 있어 더 세밀한 제어가 가능합니다. 이를 통해 배열의 원하는 부분만 선택적으로 복사할 수 있으며, 새로운 배열의 크기를 정확하게 조정할 수 있습니다. 배열의 일부만 필요하거나 특정 범위를 확장할 때 매우 유용한 방법입니다.
요약
각 방법을 사용하여 배열을 확장하고 복사하는 방식을 살펴보았습니다. 간단히 요약하면 다음과 같습니다:
Arrays.copyOf()
: 가장 간단한 방식으로, 배열 확장에 적합합니다.System.arraycopy()
: 고성능 배열 복사에 유리하며, 세밀한 제어가 가능합니다.List
로 변환 후 배열로 변환: 배열 크기를 동적으로 변경할 때 유용합니다.Streams
: 함수형 프로그래밍 스타일로 간결하게 사용할 수 있습니다.Arrays.copyOfRange()
: 배열의 특정 범위를 복사하거나 확장할 때 유용합니다.
각 방식은 상황에 따라 적합한 방법을 선택하면 됩니다. 성능이 중요한 경우 System.arraycopy()
를, 간결한 코드가 필요할 때는 Arrays.copyOf()
나 Streams
를 사용하는 것이 좋습니다. 여러분의 코딩 스타일과 문제 상황에 맞는 방법을 선택해 보세요. 상황에 따라 다양한 접근 방식을 이해하고 활용할 수 있다면, 더 효율적이고 가독성 높은 코드를 작성할 수 있을 것입니다. 😊 이러한 다양한 방법을 잘 이해하고 자신의 필요에 맞게 선택할 수 있다면, 배열을 다루는 능력을 더욱 향상시킬 수 있을 것입니다. 각각의 방법이 가지는 장단점을 고려하여, 적재적소에 활용하는 능력을 기르세요! 😊
'여러가지 > 알고리즘 & 자료구조' 카테고리의 다른 글
[프로그래머스] 뒤에서 5등까지 (0) | 2024.10.12 |
---|---|
[프로그래머스] 원소들의 곱과 합 (0) | 2024.10.12 |
[프로그래머스] 수 조작하기1 (0) | 2024.10.12 |
[백준] 문어 - 21313번 (0) | 2024.06.17 |
[백준] 쉽게푸는문제 - 1292번 (0) | 2024.06.17 |