LeetCode는 프로그래밍 문제를 풀며 코딩 실력을 향상할 수 있는 온라인 플랫폼입니다. 다양한 알고리즘 및 데이터 구조 문제를 제공하며, 면접 대비에 유용합니다. 해당 문제는, LeetCode Problems에서 볼 수 있는 난이도 '쉬움 (Easy)' 단계인 "Counting Bits" 문제입니다.
--> https://leetcode.com/problems/counting-bits/description/
문제 :
Given an integer n, return an array ans of length n + 1 such that for each i (0 <= i <= n),
ans[i] is the number of 1's in the binary representation of i.
Example 1 :
Input : n = 2
Output : [0,1,1]
Explanation : 0 --> 0 1 --> 1 2 --> 10
Example 2 :
Input : n = 5
Output : [0,1,1,2,1,2]
Explanation : 0 --> 0 1 --> 1 2 --> 10 3 --> 11 4 --> 100 5 --> 101
Constraints : 0 <= n <= 105
Follow up :
It is very easy to come up with a solution with a runtime of O(n log n).
Can you do it in linear time O(n) and possibly in a single pass?
Can you do it without using any built-in function (i.e., like __builtin_popcount in C++)?
이 문제는 정수 n에 대해 0부터 n까지의 각 정수에 대해 2진수 표현에서 1의 개수를 세는 배열을 반환하는 것입니다.
class Solution {
public int[] countBits(int n) {
int[] count = new int[n+1];
count[0] = 0;
for (int i = 1; i <= n; i++) {
count[i] = countOne(i);
}
return count;
}
public static int countOne(int n) {
int cntOne = 0;
for (int i = 0; i < Integer.SIZE; i++) {
if (((n >> i) & 1) == 1) {
cntOne++;
}
}
return cntOne;
}
}
이 코드는 주어진 정수 n에 대해 0부터 n까지의 모든 숫자의 2진수 표현에서 '1'의 개수를 구하는 기능을 수행합니다. 각 숫자의 '1'의 개수는 배열에 저장되어 반환됩니다.
코드 구조 및 작동 원리
- 배열 초기화 :
- int[] count = new int[n + 1]; : 길이 n+1의 배열을 생성하여 각 인덱스에 해당하는 숫자의 '1'의 개수를 저장합니다.
- count[0] = 0; : 0의 2진수 표현은 0이며, '1'의 개수는 0입니다.
- 반복문을 통한 각 숫자의 '1' 개수 계산 :
- for (int i = 1; i <= n; i++) : 1부터 n까지의 각 숫자에 대해 반복합니다.
- count[i] = countOne(i); : 각 숫자 i에 대해 countOne 메서드를 호출하여 '1'의 개수를 계산하고 배열에 저장합니다.
- countOne 메소드 :
- public static int countOne(int n) : 주어진 정수 n의 2진수 표현에서 '1'의 개수를 계산하는 메서드입니다.
- int cntOne = 0; : '1'의 개수를 저장할 변수를 초기화합니다.
- for (int i = 0; i < Integer.SIZE; i++) : 정수 n의 모든 비트를 검사합니다. Integer.SIZE는 자바에서 정수의 비트 수(보통 32비트)를 나타냅니다.
- ((n >> i) & 1) == 1 : n을 i만큼 오른쪽으로 시프트 하여 가장 오른쪽 비트가 '1'인지 확인합니다.
- cntOne++ : '1'이면 cntOne을 증가시킵니다.
- return cntOne; : 최종적으로 '1'의 개수를 반환합니다.
- 결과 반환 :
- 계산된 각 숫자의 '1' 개수가 저장된 배열 count를 반환합니다.
시간 복잡도
- countBits 메서드 :
- O(n * k): n까지의 각 숫자에 대해 countOne을 호출하므로, n개의 숫자를 처리합니다.
- countOne 메서드는 정수의 모든 비트(32비트)를 검사하므로 O(k)의 시간 복잡도를 가집니다. 여기서 k는 자바 정수의 비트 수입니다.
- 전체적으로 O(n * 32) ≈ O(n)의 시간 복잡도를 가집니다.
공간 복잡도
- O(n) : 길이 n+1의 배열을 생성하므로, 배열의 크기만큼 공간이 필요합니다.
이렇게 코드를 써봤는데, Submit 누르니까 결과는 생각과는 달리 조금 비효율적이게 나왔습니다.
솔직히 이거보다 어떻게 더 낫게 쓰지 싶어서 고민해봤는데, 시간 복잡도 면에서 O(32 * n) 말고도 O(n) 할만한 게 떠올라서 바로 개선시켰습니다.
class Solution {
public int[] countBits(int n) {
int[] count = new int[n + 1];
for (int i = 1; i <= n; i++) {
count[i] = count[i >> 1] + (i & 1);
}
return count;
}
}
DP (동적 프로그래밍)을 써봤는데, 아주 잘 작동합니다. 그리고 이 접근 방식이 문제가 원하는 풀이방식이라고 생각듭니다.
개선된 접근 설명 :
- count[i] = count[i >> 1] + (i & 1);는 i를 2로 나눈 몫(i >> 1)의 '1'의 개수에 현재 비트의 마지막 자리(i & 1)를 더하는 방식입니다.
- 이는 이전 계산 결과를 활용하여 더 빠르게 1의 개수를 계산합니다.
정리
- 현재 코드 : 모든 비트를 검사하여 각 숫자의 '1' 개수를 계산. O(n * 32) 시간 복잡도.
- 개선된 코드 : 이전 결과를 활용하여 더 빠르게 계산. O(n) 시간 복잡도.
이 개선된 방법은 비트 연산을 사용하여 각 숫자에 대해 빠르게 '1'의 개수를 계산하여 전체적인 효율성을 높입니다.
'LeetCode' 카테고리의 다른 글
[LeetCode] - 728. Self Dividing Numbers (0) | 2024.08.02 |
---|---|
[LeetCode] - 657. Robot Return to Origin (0) | 2024.08.02 |
[LeetCode] - 232. Implement Queue Using Stacks (0) | 2024.08.01 |
[LeetCode] - 169. Majority Element (0) | 2024.08.01 |
[LeetCode] - 2496. Maximum Value of a String in an Array (0) | 2024.08.01 |