Lv2. 2개 이하로 다른 비트

월간 코드 챌린지 시즌2 > 2개 이하로 다른 비트

프로그래머스 문제

문제 설명

양의 정수 x에 대한 함수 f(x)를 다음과 같이 정의합니다.

x보다 크고 x와 비트가 1~2개 다른 수들 중에서 제일 작은 수

시각화

2가 주어졌을 때 비트 차이가 1 ~ 2 개 다른 수 중에서 제일 작은 수는 3이다.

2개이하로다른비트-1.png

7이 주어졌을 때 비트 차이가 1 ~ 2 개 다른 수 중에서 제일 작은 수는 11이다.

2개이하로다른비트-2.png

문제 해결 과정

사실 문제를 풀 때 처음 시도한 것은 1씩 증가시키며 ^ 연산자를 사용해서 1 ~ 2 개 다른 비트를 찾아내는 것이었다. 너무 당연하게도 시간 초과가 발생하였다. 왜 자꾸 손이 가는지 모르겠다.

63231 이 주어졌을 때를 보면 1을 증가시키면 달라지게 되는 비트가 많은 것을 볼 수 있다. 이 수는 너무 길어지면 그림이 너무 작게 보여 적당한 수를 가져왔을 뿐 훨씬 더 차이가 많이 나는 수가 있다. 그러기에 ^ 연산자를 사용해서 1 ~ 2 개 다른 비트를 찾아내는 것은 굉장히 비효율적이다.

2개이하로다른비트-3.png

그렇다면 어떻게 효율적으로 계산을 할 수 있을까에 대해 고민하다가 규칙을 발견했다.

규칙 기반 풀이

주어진 수의 2진수의 맨 뒤 비트 0 과 1일 때 규칙을 찾아보면 아래와 같다.

0 일 때

주어진 수 + 1

1 일 때

맨 뒤에서부터 0을 찾고 1로 바꾼 후 그 다음 비트를 0으로 바꾼다.

0일 때는 너무 간단하니 생략하고 1일 때 도식화를 해보자.

2개이하로다른비트-4.png

문자열이 배열이 아니라 바로 위치를 바꾸지 못하니 slice 을 사용해서 처리하도록 하였다.

2개이하로다른비트-5.png

문제를 풀고 다른 사람 풀이를 보니 비트 연산자로만 풀 수 있는데 아직 그 방법이 왜 가능한지 모르겠어 이 글에 적지는 않겠다.

비트 연산 풀이

63231 과 63232 를 XOR 하면 아래와 같이 1이 연속적으로 나오게 된다. 우리가 규칙 기반 풀이에서 보았듯 0 과 1 의 자리를 바꾸면 되는 것이다.

2개이하로다른비트-7.png

아래 그림에서 첫 번 째 표는 XOR 을 한 값이다. 1일 경우 다른 비트를 의미한다. 여기서 시프트 연산자로 2만큼 이동하게 되면 뒤에 1이 2개가 사라진다.

2개이하로다른비트-8.png

이러한 방법으로 기존 값인 63231 에서 (63231 ^ 63232) » 2 를 한 값을 더한다. 즉 63231 + (63231 ^ 63232) » 2 를 하는 것이다.

이렇게 하면 맨 뒤 연산자가 0인 것을 알 수 있다. 그렇기에 +1 을 추가적으로 해주면 된다.

2개이하로다른비트-9.png

만약 a ^ b 를 했을 때 규칙 기반처럼 맨 뒤의 비트만 달라진 경우에는 000001 이런 식이기에 시프트 연산자 2번하면 0이 된다. 그렇기에 +1 을 해주면 된다. 즉 규칙 기반 풀이를 통해 비트 연산자 조합으로 풀 수 있다.

2개이하로다른비트-9.png

전체 코드

규칙 기반 풀이

def solution(numbers):
    answer = []

    for number in numbers:
        a_b = '0' + format(number, 'b')

        if a_b[-1] == '0':
            answer.append(number + 1)
            continue

        for i in range(len(a_b) - 1, -1, -1):
            if a_b[i] == '0':
                answer.append(int((a_b[0:i] + '1' + '0' + a_b[i + 2:]), 2))
                break

    return answer


print(solution([2, 7]), [3, 11])
print(solution([1]), [2]) 
solution([10 ** 15 - i * 5 for i in range(100000)]) # 오래 걸리면 시간 초과 발생 

2개이하로다른비트-6.png

비트 연산 풀이

def solution(numbers):
    return [n + ((n ^ n + 1) >> 2) + 1 for n in numbers]

2개이하로다른비트-11.png


Lv3. 입국심사

이분탐색 > 입국심사

Lv3. 인사고과

인사고과

NCloud LB & SourcePipeline 구축하기
tech collection 서비스 성능 개선하기
Selenium 복권 구매 자동화 만들어보기
디자인 패턴
책 리뷰
블로그 챌린지