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
를 반환한다.
- 배열의 길이가 같고
- 모든 인덱스의 값이 같을 때
예를 들어 :
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)
는 내부적으로 다음과 같이 동작한다. 배열은 참조형이기 때문에 주소 비교가 아니라 내용을 비교한다.
의미 | |
---|---|
| 두 배열의 내용이 완전히 동일한지 확인 |
| 두 배열이 같은 객체(주소)인지 확인 (거의 쓰지 않음) |
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;