Skip to main content

36. [Java] 조건에 맞게 수열 변환하기2

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

  • 수열 arr의 각 원소에 대해 다음 작업을 반복한다.
    • x >= 50이고 짝수 → x = x / 2
    • x < 50이고 홀수 → x = x * 2 + 1
    • 그 외 값은 그대로 둠
  • 반복 수행 결과가 이전 수열과 같아지면 멈춤
  • 가장 처음으로 arr(x) == arr(x+1)이 되는 x를 return

  • 1 ≤ arr의 길이 ≤ 1,000,000
  • 1 ≤ arr의 원소의 값 ≤ 100

정답코드

  • 이전 배열과 현재 배열이 같은지 비교해야 하므로 이 때, prev가 없으면 비교가 불가능하기 때문에 prev에 배열을 복사해둔다.
  • Arrays.copyOf(arr, arr.length)로 이전 상태를 복사
  • Arrays.equals(prev, arr)로 이전과 현재 배열 비교
  • 변화가 없을 때까지 반복하며 카운트
import java.util.*;

class Solution {
    public int solution(int[] arr) {
        int cnt = 0;
        
        while(true) {
            int[] prev = Arrays.copyOf(arr, arr.length);
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] >= 50 && arr[i] % 2 == 0) {
                    arr[i] /= 2;
                } else if (arr[i] < 50 && arr[i] % 2 == 1) {
                    arr[i] = arr[i] * 2 + 1;
                }
                // 나머지 값은 그대로
            }
            if (Arrays.equals(prev, arr)) {
                break;
            }
            cnt++;
        }
        
        return cnt;
    }
}

while문을 쓰는 이유

이 문제는 배열이 변하지 않을 때까지 특정 규칙을 반복해서 적용하라"는 조건이다. 즉, 반복 조건이 정해져있지 않다. 배열 arr이 어떤 상태에서 더 이상 변하지 않으면 멈춰야 하며, 그 시점까지 몇 번의 반복이 있었는지를 구하는 문제이다. 그래서 몇 번 반복해야 배열이 고정될지 모르기 때문에 횟수 기반 반복 (for)이 아니라 조건 기반 반복 (while)을 쓴다.만약 최대 100만 번만 반복한다는 제한이 있다고 하면 for (int i = 0; i < 1_000_000; i++) 같은 구조도 가능하지만, 이 문제는 "언젠가는 고정된 배열이 된다"는 것이 보장되어 있으므로 while가장 직관적이고 효율적이다. 매 반복마다 배열 상태를 확인해서 arr(x)arr(x+1)이 같아지는 시점이 최적의 x값이다. 이 때 배열이 고정되어 break;를 만나 while 문이 중지된다.

while (true) {
    // 배열 변화 처리
    // 변화 없으면 break;
}

Arrays.copyOf(arr, arr.length);
int[] prev = Arrays.copyOf(arr, arr.length);
  • arr : 원본 배열
  • arr.length : 복사할 길이 (즉, 배열 전체)
  • Arrays.copyOf() : 원본 배열의 내용을 그대로 복사하여 새로운 배열 생성
  • arr 배열의 내용을 deep copy해서 prev라는 새로운 배열로 만든다.

예를 들면 :

int[] arr = {1, 2, 3};
int[] prev = Arrays.copyOf(arr, arr.length);
  • arr: [1, 2, 3]
  • prev: [1, 2, 3] (값은 같지만 다른 배열 객체)

이제 arr[0] = 10;을 해도 prev[0]은 그대로 1이다. → 즉, 서로 영향을 주지 않음 (deep copy)


Arrays.equals()

if (Arrays.equals(prev, arr))에서 사용하는 Arrays.equals() 메서드는 배열의 내용이 같은지를 비교할 때 사용하는 표준 도구이다.

Arrays.equals(array1, array2)

이 메서드는두 배열이 다음 조건을 모두 만족할 때 true를 반환한다.

  1. 배열의 길이가 같고
  2. 모든 인덱스의 값이 같을 때

예를 들어 :

int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
int[] c = {1, 2, 4};

Arrays.equals(a, b); // true
Arrays.equals(a, c); // false

참고: a == b객체 참조 비교false가 나오지만 → Arrays.equals()는 내용(content)을 비교한다.
Arrays.equals(int[] a, int[] b)는 내부적으로 다음과 같이 동작한다. 배열은 참조형이기 때문에 주소 비교가 아니라 내용을 비교한다.


의미

Arrays.equals(arr1, arr2)

두 배열의 내용이 완전히 동일한지 확인

arr1 == arr2

두 배열이 같은 객체(주소)인지 확인 (거의 쓰지 않음)

if (a == b)
    return true; // 둘이 같은 객체일 경우
if (a == null || b == null)
    return false; // 한쪽이 null이면 false
if (a.length != b.length)
    return false;

for (int i = 0; i < a.length; i++) {
    if (a[i] != b[i])
        return false;
}
return true;