파이썬에서의 클래스란 사용자가 정의한 객체를 사용하기 위한 템플릿이다. 주로 객체(클래스의 인스턴스)에 적용되는 메서드를 포함한다. 파이썬의 list, dict 등의 자료형도 클래스이며 해당 클래스의 인스턴스인 변수들은 전부 객체이다.

클래스에는 속성, 메서드가 존재한다.
class User:
def __init__(self,name,age):
self.name = name
self.age = age
def __init__(self,name,age,email):
self.name = name
self.age = age
self.email = email
def introduce(self):
print("저는 {0}이고 {1}살입니다. 제 이메일은 {2}입니다. ".format(self.name, self.age, self.email))
# user1 = User("박나현",200)
user2 = User("박나현",200,"nahowo@naver.com")
# user1.introduce()
user2.introduce()class User:
value = 40
def __init__(self,name,age,email):
self.name = name
self.age = age
self.email = email
user2 = User("박나현",200,"nahowo@naver.com")
print(user2.value) # 40
print(User.value) # 40 클래스 속성은 인스턴스에게도 공유되므로 따로 변경하기 이전에는 모두 같은 값을 가진다.Leetcode에서 입력이 객체로 주어지는 문제를 풀어 보자.
예시로 이 문제를 풀어보자. 연결 리스트의 head가 주어질 때, 뒤에서 n번째 노드를 제거하고 연결 리스트의 head를 반환하는 문제이다.
우선 입력은 다음과 같이 주어진다.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
ListNode라는 클래스는 val, next라는 인스턴스 속성을 갖는다. 문제에서는 head라는 연결 리스트의 첫번째 원소가 해당 ListNode 클래스의 인스턴스로 주어진다. head.val은 해당 노드의 값, head.next는 head 다음의 ListNode 인스턴스를 가리킨다.
해당 입력이 어떻게 주어지는지 확인했으니 문제를 어떻게 접근할지 생각해 보자.
뒤에서 n번째 노드를 제거해야 하므로 head부터 연결 리스트의 끝까지 순회하는 과정이 필요하다. 노드의 개수를 센 뒤 앞에서 (노드 개수-n+1)번째 노드를 제거하면 된다.
예외 상황을 처리해 보자. n이 만약 1이라면 n-1번째의 next를 n+1의 next로 연결하고 싶어도 제거되는 n번째 원소가 맨 끝 원소이므로 연결할 수 없다. 즉 None으로 연결해줘야 한다.
또한 연결 리스트의 길이가 1이라면 head.next 부터가 None이므로 head.next.next를 접근할 때부터 오류가 발생한다. 따라서 이 경우는 단순히 head를 None으로 설정해주면 된다.
n이 연결 리스트의 길이와 같다면(= 제거해야 하는 원소가 head라면) head를 다음 노드로 이동시키면 된다.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
cnt=0
pointer=head
while pointer!=None:
pointer=pointer.next
cnt+=1
if cnt==1:
head=None
return head
num=cnt-n
if cnt==n:
head=head.next
return head
pointer=head
for i in range(num-1):
head=head.next
if n==1:
head.next=None
else:
head.next=head.next.next
head=pointer
return head
두 번째로 이 문제를 풀어보자.
단방향 연결 리스트의 head 노드가 주어졌을 때, 거꾸로 뒤집힌 연결 리스트를 반환해 보자.
입력은 위의 문제와 동일하다.
# 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: Optional[ListNode]) -> Optional[ListNode]:
단방향이므로 head에서 순회하며 돌 때 head.next 속성을 head로 변경하면 된다. 하지만 그러면 다음으로 넘어갈 수 없으니 변경하는 순서에 주의하며 연결 리스트를 뒤집어야 한다.
nxt는 head 다음 노드부터 계속 순방향으로 가리키는 노드여야 한다.
예외 상황은 연결 리스트가 비었을 때이다. head가 None이므로 head.next가 존재하지 않는다.
# 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: Optional[ListNode]) -> Optional[ListNode]:
if head==None:
return None
nxt = head.next
prv = None
head.next = prv
prv = head
while nxt != None:
head = nxt
nxt = nxt.next
head.next = prv
prv = head
return head
알고리즘을 파이썬으로 풀면서도 클래스/객체에 대해 잘 몰랐어서 한번 정리해보고 싶었다. leetcode가 아닌 플랫폼에서도 클래스를 사용해 풀이해보고 싶다. leetcode 스터디에서 풀고 있는 Easy/Medium 컬렉션에서 이런 인스턴스를 입력으로 주는 문제가 꽤 많이 나오는데, 입력 형식이 헷갈려서 넘기는 경우가 많았다. 이렇게 한번 공부를 함으로써 이후 문제를 더 편하게 풀 수 있을 것 같다.