정수 n이 주어지면 0부터 n까지의 숫자를 2진수로 변환했을 때 각각의 2진수에 1이 몇 개인지세는 문제입니다.
0부터 n까지의 수이므로 정답 배열의 크기는 n + 1이 됩니다.
가장 간단한 방법은 매번 10진수를 2진수로 변환할 때 1의 개수를 세는 방법입니다.
10진수를 2진수로 바꾸기 위해서는 2로 나눈 값과 나머지로 2진수를 구해줍니다.
2진수를 구하는게 아닌 2진수로 변환되었을 때 1의 개수를 구하면 되므로 나머지 값을 전부 더해주면 됩니다.
int CountBitHelper(int n) {
int bit = 0;
while (n) {
bit += n % 2; // 2진수가 필요한게 아닌 2진수의 1의 개수만 세면 된다.
n /= 2;
}
return bit;
}
이 방법을 0부터 n까지의 숫자에 적용해주면 됩니다.
vector<int> countBits(int n) {
vector<int> ans(n + 1, 0);
for (int i = 0; i <= n; i++)
ans[i] = CountBitHelper(i);
return ans;
}
위의 방법은 2진수로 변환하는데 O(n log)의 시간이 필요하고 n까지의 숫자에 적용하니 O(n log n)의 시간이 걸립니다.
하지만 Dynamic Programming을 사용하면 O(n)의 시간 안에 해결할 수 있습니다.
10진수에서 2진수로 변환할 때 2로 나누어 갑니다.
즉, 숫자 i의 1의 개수는 숫자 i / 2의 개수에 i % 2를 더하면 1의 개수를 구할 수 있습니다.
i가 만약 홀수라면 i % 2에 의해 1이 더해지고 짝수라면 0이 더해져 i / 2와 1의 개수가 같아집니다.
ex) 숫자 5 = 2진수 101
이때 5 / 2 = 2가 되고 2는 2진수로 10입니다.
즉, 숫자 5는 2의 2진수 값에 5 % 2 = 1을 맨 뒤에 더해준 것과 같습니다.
(10진수에서 2진수로 변환할 때 나머지 값을 맨 마지막에 추가해주는 것과 동일)
10을 밀어줘 100이 되고 1을 추가하면 101이 됩니다.
ex) 숫자 7인 경우 = 111,
7 / 2 = 3이 되고 3의 2진수 값 = 11
7 % 2 = 1 => 110 + 1 = 111으로 7과 같다.
vector<int> countBits(int n) {
vector<int> ans(n + 1, 0);
for (int i = 1; i <= n; i++)
// 10진수에서 2진수로 변환할 때 2로 나누는데
// ans[i / 2]는 i의 이전 bit의 개수와 같다.
// 그리고 i가 홀수면 i % 2로 인해 1이 추가된다.
ans[i] = ans[i / 2] + i % 2;
return ans;
}
'Algorithm 문제풀이 > Leetcode' 카테고리의 다른 글
(Easy - DFS) Leetcode - 112. Path Sum (0) | 2024.06.23 |
---|---|
(Easy - DFS) Leetcode - 100. Same Tree (0) | 2024.06.23 |
(Easy - Binary Search) Leetcode - 744. Find Smallest Letter Greater Than Target (0) | 2024.06.21 |
(Easy - Binary Search) Leetcode - 704 : Binary Search (0) | 2024.06.20 |
(Easy - Backtracking) Leetcode - 257. Binary Tree Paths (0) | 2024.06.20 |