본문 바로가기
Language/Java

[LeetCode | Java | Dynamic Programming 문제 풀이] 338. Counting Bits

by ㅇ달빛천사ㅇ 2024. 6. 6.
728x90

99클럽 | 비기너

2️⃣ 338. Counting Bits

🏷 Topic : Dynamic Programming Bit Manipulation


Easy



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++)?

Accepted    1.1M  |  Submissions    1.4M  |  Acceptance Rate    78.4%


Solution with Loop (링크🔗)

class Solution {
    public int[] countBits(int n) {
        int[] answer = new int[n + 1];
        int n2 = 1;

        for (int i = 1; i <= n; i++) {            
            if (i == n2) {
                answer[i] = 1;
                n2 *= 2;
            } else {
                answer[i] = answer[i - n2 / 2] + 1;
            }
        }

        return answer;
    }
}
채점 결과
 
 


Solution with Loop and Arithmetic Operator

class Solution {
    public int[] countBits(int n) {
        int[] answer = new int[n + 1];

        for (int i = 0; i <= n; i++) {
            int n2 = i;

            while(n2 != 0 ) {
                if (n2 % 2 == 1) {
                    answer[i]++;
                }
                n2 /= 2;
            }
        }

        return answer;
    }
}
채점 결과

💥 오늘 만난 문제 & 나의 시도 💦 & 해결 방법 👍

처음에 문제를 2번째 풀이 방법으로 풀었는데 10ms가 나와서
더 빠른 코드를 써보고 싶어서 한참을 도전하다가 재귀함수 코드 쓰는 것은 포기하고😵
다른 코드로 시도하여 2ms가 걸리는 코드를 작성할 수 있었다.

  1. 매개변수로 정수 n이 주어진다.
  2. 길이가 n + 1인 정수 배열 ans를 만든다.
  3. ansi번째 인덱스의 값은
    10진수 i를 이진법으로 표현했을 때, 그 이진법 표현에 들어 있는 `1의 개수이다.
  4. ans를 반환한다.

10진법 --> 2진법 : 1 개수
0 --> 0 : 0

1 --> 1 : 1

2 --> 10 : 1
3 --> 11 : 2

4 --> 100 : 1
5 --> 101 : 2
6 --> 110 : 2
7 --> 111 : 3
...

  • $2^{n}$의 1의 개수는 무조건 1
  • 그 다음 오는 정수들은 0부터 $2^{n} - 1$까지의 수에 1을 더한 수가 순차적으로 온다.

이를 이용하여 반복문으로 ans의 각 요소에 값을 할당해 보자.


1. 반환할 정수형 배열 answer을 초기화 하자.

int[] answer = new int[n + 1];

2. 반복문을 돌때, 인덱스가 2의 거듭제곱인지 아닌지 체크할 변수 n21로 초기화

int n2 = 1;

3. 배열의 1번째 인덱스부터 n번째 인덱스까지 반복문을 돌면서 값을 할당하자.

  • 만약 인덱스 i가 2의 거듭제곱이면(in2가 같으면), answeri번째 인덱스에 1을 할당하고 n2에 곱하기 2를 해 줌.
if (i == n2) {
    answer[i] = 1;
    n2 *= 2;
}
  • i가 2의 거듭제곱이 아니면(in2가 다르면), answeri번째 인덱스에 answeri - n2 / 2번째 인덱스의 값 + 1을 할당.
else {
    answer[i] = answer[i - n2 / 2] + 1;
}

4. answer을 반환

return answer;

💬 무엇을 새롭게 알았는지

그래도 포기하지 않고 코드를 써서 8ms 더 빠른 코드를 작성할 수 있었다.
포기하지 않고 시도해 본 경험을 얻을 수 있었다.


📚 References(참고 자료)


 🆙 Next Level

+ 69회 현충일 기념 66줄 코드 쓰기 문제 : 코딩테스트 연습 | 코딩 기초 트레이닝 | 날짜 비교하기

728x90


Top