문제
[09527] 1의 개수 세기
문제는 단순하다, 주어진 두 수 사이의 1의 개수를 세는 것이다.
분석
1의 개수를 세기 위하여, 0에서부터 15까지 2진수를 바꾸면 다음과 같다.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 8 |
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 8 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 8 |
0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 8 |
0 | 1 | 1 | 2 | 1 | 2 | 2 | 3 | 1 | 2 | 2 | 3 | 2 | 3 | 3 | 4 | 32 |
각 정수를 2진수를 바꾸면, 일반적으로 1씩 늘어가는 탓에 1의 개수가 불규칙해 보인다.
하지만 그렇다고 각 수별로 1의 개수를 세면, 주어진 수의 크기에 의하여 시간초과
가 될 것이다.
따라서 좀 더 효율적으로 문제에 접근할 필요가 있다.
시점을 바꿔 각 자리 수 별로 보면 새로운 규칙을 발견할 수 있다.
- 제일 작은 비트는 [0] * 1, [1] * 1의 반복
- 그 다음 비트는 [0] * 2, [1] * 2의 반복
- 그 다음 비트는 [0] * 4, [1] * 4의 반복
즉 각 자리 값의 개수 만큼 0 과 1이 반복되는 것을 알 수 있다.
따라서 위와 같이 정리할 수 있다.
풀이
1의 누적합 개수를 세는 함수를 만드는데, 함수 내에서의 동작은 다음과 같다.
- 지표는 2를 시작으로 반복문을 시작하는데, 지표가 주어진 숫자보다 커지면 종료한다.
- 반복문 내에서는 주어진 수를 지표 값만큼 나눈 몫을 구하고, 몫에 지표의 절반 값을 곱해 더한다.
- 주어진 수를 지표 값으로 나머지 연산한 값에서 지표의 절반 값을 빼고 더한다.
- 하지만 4의 값이 음수일 경우 무시한다.
- 반복문 내에서는 지표에 2를 곱하며 다음 반복문을 시작한다.
따라서 최종 코드는 다음과 같다.
https://github.com/onsoim/BOJ/tree/master/Solved/01000-09999/09527
'0x30 Algorithm' 카테고리의 다른 글
[Java/Kotlin] ArrayList v.s. LinkedList (0) | 2022.01.26 |
---|---|
Testcase 모음집 (0) | 2021.11.20 |