# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head:ListNode) -> ListNode:
node, prev = head, None
while node:
next, node.next = node.next, prev
prev, node = node, next
return prev
#연결 리스트를 파이썬 리스트로 변환
def toList(self, node: ListNode) -> ListNode:
list: List = []
while node:
list.append(node.val)
node = node.next
return list
#파이썬 리스트를 연결 리스트로 변환
def toReversedLinkedList(self, result: ListNode) -> ListNode:
prev: ListNode = None
for r in result:
node = ListNode(r)
node.next = prev
prev = node
return node
#두 연결 리스트의 덧셈
def addTwoNumbers(self, l1:ListNode, l2:ListNode) -> ListNode:
a = self.toList(self.reverseList(l1))
b = self.toList(self.reverseList(l2))
resultStr = int(''.join(str(e) for e in a)) + \
int(''.join(str(e) for e in b))
#최종 계산 결과 연결 리스트 변환
return self.toReversedLinkedList(str(resultStr))
먼저, 역순으로 된 연결리스트를 뒤집어야 한다.
다음으로 덧셈 연산을 위해 연결 리스트를 파이썬의 리스트로 변경한다.
리스트를 다시 연결 리스트로 변경한다.
여기서는 순서대로 엮어 나가는 방식으로 구현했는데, 이렇게 하면 뒤집힌 연결 리스트가 된다.
이 문제에서는 출력 또한 역순으로 하도록 요구하고 있기에 이 상태 그대로 내보내면 된다.
다시 뒤집어야 한다면 위의 함수에 다시 대입하면 된다.
이제 덧셈 연산을 하면 되는데, 이를 위해서는 리스트를 int 형태로 결합해야 한다.
이전에 문자열 리스트를 str으로 면경하는 과정을 살펴본 바 있다.
''.join(s)
와 같은 형식으로 처리가 가능하다.
여기서는 str(e)
로 각 항목을 문자로 변경한 다음 join()
으로 합쳤다.
또한 , 덧셈 연산을 위해서 int로 다시 변경해주어야 한다.
resultStr = int(''.join(str(e) for e in a)) + \
int(''.join(str(e) for e in b))
마지막으로, 최종 계산 결과를 연결 리스트로 바꿔준다.
toReversedLinkedList()
를 사용하면 쉽게 변환할 수 있다.
단, 여기서는 문자열을 입력값으로 받기 때문에 다음과 같이 str()
으로 한 번 변환하는 작업이 필요하다
return self.toReversedLinkedList(str(resultStr))
논리 회로의 전가산기(Full Adder)과 유사한 형태를 구현해보자
<전가산기 진리표(Truth Table)>
<전가산기 회로도>
입력값 A, B는 오른쪽으로는 XOR 게이트를 통과한 결과가 나아가고, 아래로는 AND 게이트를 통과한 결과가 나아간다.
그렇게 함과 다음 자리올리수 위치에 도달한 결과가 진리표이다.
실제로 덧셈연산을 수행하는 논리회로의 원리며, 산술 논리 장치(Arithmetic Logic Unit)를 구성하는 디지털 회로의 일부분이다.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1:ListNode, l2:ListNode) -> ListNode:
root = head = ListNode(0)
carry = 0
while l1 or l1 or carry:
sum = 0
#두 입력값의 합 계산
if l1:
sum += l1.val
l1 = l1.next
if l2:
sum += l2.val
l2 = l2.next
# 몫(자리올림수)과 나머지(값) 계산
# carry = sum + carry // 10
# val = sum + carry % 10
carry, val = divmod(sum + carry, 10)
head.next = ListNode(val)
head = head.next
return root.next
연산 결과로 나머지(Remainder) 를 취하고 몫(Quotient) 은 자리 올림수 형태로 올리는 전가산기의 전체적인 구조만 참고해 풀이한다.
l1, l2는 전가산기 회로도에서 A, B의 역할과 동일하다. 두 입력값의 연산을 수행하고 다음과 같이 자릿수가 넘어갈 경우에는 자리 올리수를 설정할 것이다.
carry, val = divmod(sum + carry, 10)
divmod( )는 파이썬의 내장 함수로, 몫과 나머지로 구성된 튜플을 리턴한다.
divmod의 결과로, 가산 결과가 두 자릿수가 될 경우, 몫은 자리올림수로 설정해 다음번 연산에 사용되게 하고, 나머지는 값으로 취한다.
다음으로 이 값을 연결 리스트로 만들어주면 된다.
원래 가산기는 논리 회로를 이용해 이진 연산을 수행하지만 여기서는 전체적인 구조만 참고하여 십진 연산에 응용해봤다.