[Java] 배열의 길이를 2의 거듭제곱으로 만들기

Hood·2025년 9월 19일

Java

목록 보기
1/5
post-thumbnail

들어가기 전

현재 필자는 코틀린에서 자바로 마이그레이션 중
익숙한 코틀린을 뒤로하고 Java로 프로그래머스 입문 문제를 풀다가 다음과 같은 문제점을 발견하게 되었다.


사건의 발단

문제를 풀기 위해 다음과 같은 코드를 작성했다.
주어진 배열의 길이를 그것보다 크거나 같은 최소의 2의 거듭제곱으로 만들고
남는 공간은 0으로 채우는 문제였다.

class Solution {
    public ArrayList<Integer> solution(int[] arr) {
        ArrayList<Integer> answer = new ArrayList<>();
        int arrSize = arr.length;
        int pow = 1;

        while(pow < arrSize){
            pow *= 2;
        }
        
        for(int i=0; i < pow; i++){
            if(i < arrSize){
                answer.add(arr[i]);
            } else {
                answer.add(0);
            }
        }
        return answer;
    }
}

나의 초기 로직

  1. 결과를 담을 ArrayList를 선언한다.
  2. while문으로 arr의 길이(arrSize)보다 크거나 같은 최소 2의 거듭제곱 수(pow)를 구한다.
  3. pow만큼 for문을 반복하며, arr의 범위 내에서는 기존 값을, 범위를 벗어나면 0을 추가한다.

코드를 작성하고 22번 케이스가 실패하여 질문하기를 보다 발견한 문제점이 생겼다.

"이러면 2의 0승일 때는 어떻게 처리하지?"

배열 길이가 1일 때(arrSize = 1), while문은 돌지 않고 pow는 1이 된다. for문은 1번 돌고 arr[0]의 값을 넣는다. 결과는 맞지만, 이 로직이 과연 최선일까? for문 안의 if-else가 너무 비효율적이고 지저분하게 느껴졌다.


코드 최적화 과정

1. 문제점 파악

가장 큰 비효율은 for 문 안에서 매번 if (i < arrSize) 조건을 검사하는 것이다.
이는 불필요한 연산의 반복이며 역할을 분리하는 것이 좋다고 생각했다.

  • 기존 배열 요소를 전부 복사한다.
  • 모자란 길이만큼 0을 추가한다.

2. Java 특성 활용하기

Java는 int타입의 배열을 생성하면 모든 요소가 자동으로 0으로 초기화된다.
그렇다면 0을 추가하는 2번 과정은 필요없다.

그럼 내가 개선할 수 있는 점은

  • 최종 목표 길이(pow)만큼의 int[] 배열을 생성한다.
  • 생성된 배열의 앞부분의 원본 배열(arr)의 값들을 복사해 덮어쓴다.

값을 복사할 때 for문을 쓰는 것보다 System.arraycopy() 메서드를 사용할 수 있었다.
내부에서 네이티브 코드로 동작하며 훨씬 빠른 속도로 메모리 블록을 통째로 복사할 수 있었다.


개선된 최종 Java 코드

위의 최적화 과정을 통해 효율적인 코드를 완성할 수 있었다.

// 최종 개선 코드
class Solution {
    public int[] solution(int[] arr) {
        int arrSize = arr.length;
        int pow = 1;
        while (pow < arrSize) {
            targetLength *= 2;
        }
        int[] answer = new int[pow];
        /**
        arraycopy(원본 배열, 원본 배열의 복사를 시작할 인덱스,
        복사될 배열, 복사될 배열에서 데이터를 저장할 시작 인덱스, 복사할 요소의 갯수)
        **/
        System.arraycopy(arr, 0, answer, 0, arrSize);
        return answer;
    }
}

ArrayList를 굳이 쓸 필요도 없고 복잡한 for-if-else문도 사라졌다.

Kotlin 코드와 비교

fun solution(arr: IntArray): IntArray {
    var pow = 1
    while (pow < arr.size) {
        pow *= 2
    }
    
    return arr.copyOf(pow)
}

이렇게 보면 Kotlin은 매우 간결하고 직관적인것 같다.


결론

Java에서는 배열의 기본 특성과 고성능 유틸리티를 잘 이해하고 활용해야 효율적인 코드를 짤 수 있었다.
동시에 Kotlin이 왜 개발자 친화적인 언어인지 확인할 수 있었다.

profile
달을 향해 쏴라, 빗나가도 별이 될 테니 👊

0개의 댓글