행렬 M과 같은 행·열 크기를 가진 목표 행렬 T가 있다고 가정해 보겠습니다. 여기서 '연산'이란 행렬의 특정 열 하나를 뒤집는 작업으로, 해당 열에 있는 모든 1은 0으로, 모든 0은 1로 바뀝니다. 이때 행의 순서는 자유롭게 재배열할 수 있으며 비용이 들지 않습니다. 이 조건에서 M을 T로 변환하는 데 필요한 최소 연산 횟수를 구하는 프로그램을 작성해야 하며, 변환이 불가능하다면 -1을 반환합니다.
예를 들어 입력이 다음과 같다고 해보겠습니다.
M =
| 0 | 0 |
| 1 | 0 |
| 1 | 1 |
T =
| 0 | 1 |
| 1 | 0 |
| 1 | 1 |
이 경우 출력은 1입니다. 먼저 행의 순서를 다음처럼 재배열합니다.
| 0 | 0 |
| 1 | 1 |
| 1 | 0 |
그다음 첫 번째 열(index 0)을 한 번 뒤집으면,
| 0 | 1 |
| 1 | 0 |
| 1 | 1 |
목표 행렬 T와 정확히 일치하게 됩니다.
풀이 접근 방법
이 문제는 각 행을 이진수 값으로 취급하고 XOR 연산을 활용하면 효율적으로 해결할 수 있습니다. 단계별로 살펴보겠습니다.
- 빈 리스트
nums1과nums2를 준비합니다. - 행렬 M의 각 행에 대해:
ths = 0으로 초기화합니다.- 행이 빌 때까지 마지막 원소를 꺼내
ths = (ths * 2) + 원소로 갱신합니다. - 완성된 값을
nums1의 끝에 추가합니다.
- 목표 행렬 T에 대해서도 동일한 과정을 수행해
nums2를 만듭니다. ret = 무한대(infinity)로 초기화합니다.nums1의 각 값num에 대해:cts: nums1의 원소별 빈도수를 저장한 맵(Counter)을 생성하고,cts[num] -= 1로 현재 선택된 행을 제외합니다.my_xor = num XOR nums2[0]을 계산합니다. 이 값은 각 행에 적용해야 할 뒤집기 패턴을 의미합니다.- i를 1부터 nums2의 크기까지 순회하며:
needed = my_xor XOR nums2[i]를 계산합니다.cts[needed]가 0이라면 필요한 행 패턴이 존재하지 않으므로 반복문을 탈출합니다.- 그렇지 않다면
cts[needed] -= 1로 해당 패턴을 소진합니다.
- 반복문이 중단 없이 완료되면(모든 행이 매칭되면)
ret = min(ret, my_xor의 1비트 개수)로 갱신합니다. 1비트 개수가 곧 뒤집어야 할 열의 개수입니다.
ret가 무한대가 아니면ret을, 그렇지 않으면 -1을 반환합니다.
구현 예제 코드
class Solution:
def solve(self, matrix, target):
nums1 = []
nums2 = []
for row in matrix:
ths = 0
while row:
ths = (ths<<1) + row.pop()
nums1.append(ths)
for row in target:
ths = 0
while row:
ths = (ths<<1) + row.pop()
nums2.append(ths)
ret=float('inf')
from collections import Counter
for num in nums1:
cts = Counter(nums1)
cts[num] -= 1
my_xor = num^nums2[0]
for i in range(1,len(nums2)):
needed = my_xor^nums2[i]
if not cts[needed]:
break
cts[needed]-=1
else:
ret=min(ret,bin(my_xor).count('1'))
return ret if ret!=float('inf') else -1
ob = Solution()
M = [
[0, 0],
[1, 0],
[1, 1]
]
T = [
[0, 1],
[1, 0],
[1, 1]
]
print(ob.solve(M,T))
입력
M = [[0, 0],[1, 0],[1, 1]]
T = [[0, 1],[1, 0],[1, 1]]
출력
1
핵심 포인트 정리
- 행 → 이진수 변환: 각 행을 정수 값으로 변환하면 행 비교와 XOR 계산이 간단해집니다.
- XOR의 역할: 두 행 사이의 XOR 결과는 어떤 열들을 뒤집어야 하는지를 나타냅니다.
- 1비트 개수 = 연산 횟수: XOR 값에서 1인 비트의 개수가 곧 뒤집어야 할 열의 수입니다.
- Counter 활용: 행 패턴의 빈도를 관리해 모든 행이 목표 행렬과 매칭 가능한지 효율적으로 검증합니다.