HTD
[Python] 백준 2866번: 문자열 잘라내기(시간 복잡도 1등) 본문
https://www.acmicpc.net/problem/2866
2866번: 문자열 잘라내기
첫 번째 줄에는 테이블의 행의 개수와 열의 개수인 R과 C가 주어진다. (2 ≤ R, C ≤ 1000) 이후 R줄에 걸쳐서 C개의 알파벳 소문자가 주어진다. 가장 처음에 주어지는 테이블에는 열을 읽어서 문자
www.acmicpc.net
- (첫번째 해결 방법) 접근

문자열을 거꾸로 생각하고 여기에 Trie를 접목하였다.
import sys
input = sys.stdin.readline
class Node:
  __slots__ = ['childs']
  def __init__(self):      
    self.childs = {}
class Trie:
  __slots__ = ['root']
  def __init__(self):
    self.root = Node()
  def insert(self, strr):
    cur = self.root
    level = 1
    overrapped_level = 0
    for c in strr:
      if not cur.childs.get(c):    
        cur.childs[c] = Node() 
      else:
        overrapped_level = level
      cur = cur.childs[c] 
      level += 1
  
    return R - overrapped_level - 1
              
if __name__ == '__main__':
  R, C = map(int, input().split())
  strs = [str(input().rstrip()) for _ in range(R)]
  res = float('inf')   
  trie = Trie()        
  for strr in zip(*strs[::-1]):     
    res = min(res, trie.insert(strr))
  print(res)
- (두번째 해결 방법) 접근
row별로 지웠을 때 같은 문자가 없다면 0, 있다면 1이라고 해보자. 결과는 무조건 '0000...111111...'와 같은 식으로 나뉘게 된다.(물과 기름이 안 섞이듯이) 이는 마치 정렬된 것과 같으므로 이분 탐색을 할 수 있다.
- (두번째 해결방법) 풀이
이분 탐색을 1부터 R-1까지의 범위로 시작하며, 목적은 같은 문자열이 없는 row의 최대값을 구하는 것이다. is_there_same_string_pair()라는 함수로, mid 이상의 row에 같은 문자열 쌍이 한 개라도 있는지 확인한다. 여기서 참이 나오면 범위를 위쪽으로 올려주고, 거짓이면 범위를 아래로 내려주는데, 이로써 이분 탐색의 목적을 달성할 수 있다.
is_there_same_string_pair() 함수는 각각의 문자열이 어느 위치(y)에 있는지를 c_to_y_indices에 저장해준 뒤, 특정 문자가 2회 이상 나왔을 경우 combination으로 y의 쌍을 선택하여 같은 문자열인지 체크해준다.
import sys, itertools
input = sys.stdin.readline
       
def is_same_string_pair(start_x, y1, y2):
  for i in range(start_x, R):
    if strs[i][y1] != strs[i][y2]:
      return False
  return True
def is_there_same_string_pair(x):
  c_to_y_indices = {} # row: aaba -> {'a':[0,1,3], 'b':[2]}         
  for j in range(C):
    c = strs[x][j]
    if c_to_y_indices.get(c):
      c_to_y_indices[c].append(j)
    else:
      c_to_y_indices[c] = [j]
  # Check if there is at least one same string pair
  for c, y_indices in c_to_y_indices.items():
    if len(y_indices) < 2: continue
                                      
    for y1, y2 in itertools.combinations(y_indices, 2):
      if is_same_string_pair(x+1, y1, y2):
        return True
  return False  
def find_biggest_index_with_no_same_string():          
  top, bottom = 1, R-1
  while top <= bottom:
    mid = (top + bottom)//2
    if is_there_same_string_pair(mid):  
      bottom = mid - 1  
    else:  
      top = mid + 1   
  return top - 1
if __name__ == '__main__':
  R, C = map(int, input().split())
  strs = [str(input().rstrip()) for _ in range(R)]
  print(find_biggest_index_with_no_same_string())

'Algorithm > 백준' 카테고리의 다른 글
| [Python] 18186번: 라면 사기 (Large) (0) | 2023.06.19 | 
|---|---|
| [Python] 백준 15653번: 구슬 탈출 4 (0) | 2022.03.22 | 
| [Python] 백준 13168번: 내일로 여행 (0) | 2022.03.18 | 
| [Python] 백준 14437번: 준오는 심술쟁이!! (0) | 2022.03.16 | 
| [Python] 백준 5670번: 휴대폰 자판 (0) | 2022.03.14 |