문제:

회문(回文) 또는 팰린드롬(palindrome)은 앞 뒤 방향으로 볼 때 같은 순서의 문자로 구성된 문자열을 말한다. 예를 들어 ‘abba’ ‘kayak’, ‘reviver’, ‘madam’은 모두 회문이다. 만일 그 자체는 회문이 아니지만 한 문자를 삭제하여 회문으로 만들 수 있는 문자열이라면 우리는 이런 문자열을 “유사회문”(pseudo palindrome)이라고 부른다. 예를 들어 ‘summuus’는 5번째나 혹은 6번째 문자 ‘u’를 제거하여 ‘summus’인 회문이 되므로 유사회문이다.

여러분은 제시된 문자열을 분석하여 그것이 그 자체로 회문인지, 또는 한 문자를 삭제하면 회문이 되는 “유사회문”인지, 아니면 회문이나 유사회문도 아닌 일반 문자열인지를 판단해야 한다. 만일 문자열 그 자체로 회문이면 0, 유사회문이면 1, 그 외는 2를 출력해야 한다. 

입력:

입력의 첫 줄에는 주어지는 문자열의 개수를 나타내는 정수 T(1 ≤ T ≤ 30)가 주어진다. 다음 줄부터 T개의 줄에 걸쳐 한 줄에 하나의 문자열이 입력으로 주어진다. 주어지는 문자열의 길이는 3 이상 100,000 이하이고, 영문 알파벳 소문자로만 이루어져 있다.

출력:

각 문자열이 회문인지, 유사 회문인지, 둘 모두 해당되지 않는지를 판단하여 회문이면 0, 유사 회문이면 1, 둘 모두 아니면 2를 순서대로 한 줄에 하나씩 출력한다.

풀이방법:

 일반적인 회문 문제와는 다르게 한 번의 기회를 더 제공하는 '유사회문'이라는 추가 조건이 더 있다. 따라서 일반적인 회문을 판정하는 함수에 추가적으로 하나의 문자를 삭제하고 추가로 회문인지 판단하는 함수를 더 추가하도록 한다. 이 때, 하나의 문자를 제거할 때, 왼쪽의 문자, 오른쪽의 문자를 한번씩 모두 제거하여 유사회문이 되는지 판단하여야 한다. 만약 한쪽을 우선적으로 판단하면 오류가 되는 케이스를 발견할 수 있다.

 따라서 일반적인 회문이라면 0을 반환하고, 하나를 제거해야 하는 상황인데 왼쪽, 오른쪽을 둘 다 확인했을 때, 하나가 가능하다면 1, 둘 다 불가능하다면 2를 반환하여 출력을 할 수 있도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def next_palindrome(s, left, right):
    while left < right:
        if s[left]==s[right]:
            left+=1
            right-=1
        else:
            return 0
    return 1
 
def is_palindrome(s, left, right):
    while left < right:
        if s[left]==s[right]:
            left+=1
            right-=1
        else:
            left_count = next_palindrome(s, left+1, right)
            right_count = next_palindrome(s, left, right-1)
            if left_count or right_count:
                return 1
            else:
                return 2
    return 0
 
= int(input())
for _ in range(T):
    string = input()
    answer = is_palindrome(string, 0len(string)-1)
    if answer >= 2:
        answer = 2
    print(answer)
cs

문제링크:

https://www.acmicpc.net/problem/17609

 

17609번: 회문

각 문자열이 회문인지, 유사 회문인지, 둘 모두 해당되지 않는지를 판단하여 회문이면 0, 유사 회문이면 1, 둘 모두 아니면 2를 순서대로 한 줄에 하나씩 출력한다.

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2195. 문자열 복사  (0) 2022.03.10
[BOJ]2212. 센서  (0) 2022.03.08
[BOJ]1766. 문제집  (0) 2022.03.01
[BOJ]1256. 사전  (0) 2022.02.24
[BOJ]10164. 격자상의 경로  (0) 2022.02.22

문제:

수빈이는 A와 B로만 이루어진 영어 단어가 존재한다는 사실에 놀랐다. 대표적인 예로 AB (Abdominal의 약자), BAA (양의 울음 소리), AA (용암의 종류), ABBA (스웨덴 팝 그룹)이 있다.

이런 사실에 놀란 수빈이는 간단한 게임을 만들기로 했다. 두 문자열 S와 T가 주어졌을 때, S를 T로 바꾸는 게임이다. 문자열을 바꿀 때는 다음과 같은 두 가지 연산만 가능하다.

  • 문자열의 뒤에 A를 추가한다.
  • 문자열을 뒤집고 뒤에 B를 추가한다.

주어진 조건을 이용해서 S를 T로 만들 수 있는지 없는지 알아내는 프로그램을 작성하시오. 

입력:

첫째 줄에 S가 둘째 줄에 T가 주어진다. (1 ≤ S의 길이 ≤ 999, 2 ≤ T의 길이 ≤ 1000, S의 길이 < T의 길이)

출력:

S를 T로 바꿀 수 있으면 1을 없으면 0을 출력한다.

풀이방법:

 S를 T로 바꾸는 방법에 대해 찾는 것이 아니라 T에서 S로 그리디하게 되돌아가는 방법으로 만들 수 있는지 없는지 확인한다.

 두 가지 연산은 맨 뒤에 A가 추가되거나 B가 추가된다. 따라서 매번 T의 맨 끝에 따라 연산을 수행하도록 한다. 맨 마지막이 A라면 A만 떼어내고, B라면 B를 떼어내고 뒤집어서 새로 T를 만들어내도록 한다.

 T와 S의 길이가 같아졌을 때, S와 T가 같다면 1을 같지않다면 0을 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
= input()
= input()
answer = False
while True:
    if len(S) == len(T):
        if S==T:
            answer = True
        break
    if T[-1]=='A':
        T = T[:-1]
    elif T[-1]=='B':
        T = T[:-1][::-1]
if answer:
    print(1)
else:
    print(0)
cs

문제링크:

https://www.acmicpc.net/problem/12904

 

12904번: A와 B

수빈이는 A와 B로만 이루어진 영어 단어가 존재한다는 사실에 놀랐다. 대표적인 예로 AB (Abdominal의 약자), BAA (양의 울음 소리), AA (용암의 종류), ABBA (스웨덴 팝 그룹)이 있다. 이런 사실에 놀란 수

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]3020. 개똥벌레  (0) 2021.09.30
[BOJ]6593. 상범 빌딩  (0) 2021.09.29
[BOJ]1722. 순열의 순서  (0) 2021.09.27
[BOJ]1351. 무한 수열  (0) 2021.09.24
[BOJ]1202. 보석 도둑  (0) 2021.09.23

문제:

남극에 사는 김지민 선생님은 학생들이 되도록이면 많은 단어를 읽을 수 있도록 하려고 한다. 그러나 지구온난화로 인해 얼음이 녹아서 곧 학교가 무너지기 때문에, 김지민은 K개의 글자를 가르칠 시간 밖에 없다. 김지민이 가르치고 난 후에는, 학생들은 그 K개의 글자로만 이루어진 단어만을 읽을 수 있다. 김지민은 어떤 K개의 글자를 가르쳐야 학생들이 읽을 수 있는 단어의 개수가 최대가 되는지 고민에 빠졌다.

남극언어의 모든 단어는 "anta"로 시작되고, "tica"로 끝난다. 남극언어에 단어는 N개 밖에 없다고 가정한다. 학생들이 읽을 수 있는 단어의 최댓값을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 단어의 개수 N과 K가 주어진다. N은 50보다 작거나 같은 자연수이고, K는 26보다 작거나 같은 자연수 또는 0이다. 둘째 줄부터 N개의 줄에 남극 언어의 단어가 주어진다. 단어는 영어 소문자로만 이루어져 있고, 길이가 8보다 크거나 같고, 15보다 작거나 같다. 모든 단어는 중복되지 않는다.

출력:

첫째 줄에 김지민이 K개의 글자를 가르칠 때, 학생들이 읽을 수 있는 단어 개수의 최댓값을 출력한다.

풀이방법:

 일반적인 브루트포스 방법을 사용하면 시간초과가 날 수 있기 때문에, 비트마스킹이라는 방법을 사용했다. "anta", "tica"에서 사용되는 "a","n","t","i","c"를 제외하고 나머지 알파벳에 대해서 20개의 비트가 있다고 가정하고, 사용하면 1을 올리고, 사용하지 않으면 0으로 냅두는 방법을 사용한다. 

 항상 5개의 알파벳은 사용해야 하기 때문에, k가 5보다 작으면 읽을 수 있는 단어가 없다. 이외의 경우에는 가능한 알파벳에서 k-5개의 알파벳을 뽑은 뒤(가능한 모든 조합에 대해), 비트마스킹을 통해 갯수를 세고, 그 중 최댓값을 반환하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from itertools import combinations
 
def word2bin(word):
    answer = 0b0
    for x in word:
        answer |= (1<<(ord(x)-ord('a')))
    return answer
    
 
n, k = map(int,input().split())
words = []
for _ in range(n):
    words.append(set(input()).difference(list('anta')+list('tica')))
if k < 5:
    print(0)
else:
    bin_list = [word2bin(word) for word in words]
    candidate = ['b','d','e','f','g','h','j','k','l','m','o','p','q','r','s','u','v','w','x','y','z']
    answer = 0
    for candi in combinations(candidate,k-5):
        temp = word2bin(candi)
        count = 0
        for bin_ in bin_list:
            if bin_ & temp == bin_:
                count+=1
        answer = max(answer,count)
    print(answer)
cs

문제링크:

https://www.acmicpc.net/problem/1062

 

1062번: 가르침

첫째 줄에 단어의 개수 N과 K가 주어진다. N은 50보다 작거나 같은 자연수이고, K는 26보다 작거나 같은 자연수 또는 0이다. 둘째 줄부터 N개의 줄에 남극 언어의 단어가 주어진다. 단어는 영어 소문

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]18870. 좌표 압축  (0) 2021.07.27
[BOJ]2589. 보물섬  (0) 2021.07.22
[BOJ]5397. 키로거  (0) 2021.07.15
[BOJ]5557. 1학년  (0) 2021.07.13
[BOJ]10973. 이전 순열  (0) 2021.07.08

문제:

총 N개의 문자열로 이루어진 집합 S가 주어진다.

입력으로 주어지는 M개의 문자열 중에서 집합 S에 포함되어 있는 것이 총 몇 개인지 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 문자열의 개수 N과 M (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10,000)이 주어진다.

다음 N개의 줄에는 집합 S에 포함되어 있는 문자열들이 주어진다.

다음 M개의 줄에는 검사해야 하는 문자열들이 주어진다.

입력으로 주어지는 문자열은 알파벳 소문자로만 이루어져 있으며, 길이는 500을 넘지 않는다. 집합 S에 같은 문자열이 여러 번 주어지는 경우는 없다.

출력:

첫째 줄에 M개의 문자열 중에 총 몇 개가 집합 S에 포함되어 있는지 출력한다.

풀이방법:

이 문제는 다른 방법을 사용하면 쉽게 풀 수 있겠지만, 트라이 자료구조를 활용해서 풀어보았다. 생각보다 시간제한이 어려웠던 문제라서 최대한 시간을 줄이고자, Node를 정의해서 풀었던 다른 문제들과는 달리 하나의 class만으로 해결해보도록 구성해보았다.

class Trie(object):
    @classmethod
    def __init__(self):
        self.root = {}
        self.terminate = 'eof'
        
    @classmethod
    def insert(self, string):
        currNode = self.root
        for chr_ in string:
            if chr_ not in currNode:
                currNode[chr_] = {}
            currNode = currNode[chr_]
        currNode[self.terminate] = string
        
    @classmethod
    def search(self,string):
        currNode = self.root
        for chr_ in string:
            if chr_ in currNode:
                currNode = currNode[chr_]
            else:
                return False
        if 'eof' in currNode.keys():
            return True
        else:
            return False

n, m = map(int,input().split())
T = Trie()
for _ in range(n):
    T.insert(input())
answer = 0
for _ in range(m):
    if T.search(input()):
        answer+=1
        
print(answer)

문제링크:

https://www.acmicpc.net/problem/14425

 

14425번: 문자열 집합

첫째 줄에 문자열의 개수 N과 M (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10,000)이 주어진다.  다음 N개의 줄에는 집합 S에 포함되어 있는 문자열들이 주어진다. 다음 M개의 줄에는 검사해야 하는 문자열들이 주어

www.acmicpc.net

 

'Algorithm' 카테고리의 다른 글

[BOJ]11559. Puyo Puyo  (0) 2021.09.07
[BOJ]3190. 뱀  (0) 2021.08.19
[BOJ]1520. 내리막길  (0) 2021.08.17
[BOJ]1987. 알파벳  (0) 2021.08.10
[Programmers]Lv 1.완주하지 못한 선수  (0) 2019.02.17

문제:

개미는(뚠뚠) 오늘도(뚠뚠) 열심히(뚠뚠)  일을 하네.

개미는 아무말도 하지 않지만 땀을 뻘뻘 흘리면서 매일 매일을 살길 위해서 열심히 일을 하네.

한 치 앞도(뚠뚠) 모르는(뚠뚠) 험한 이 세상(뚠뚠) 그렇지만(뚠뚠) 오늘도 행복한 개미들!

우리의 천재 공학자 윤수는 이 개미들이 왜 행복한지 궁금해졌다.

행복의 비결이 개미가 사는 개미굴에 있다고 생각한 윤수는 개미굴의 구조를 알아보기 위해 로봇 개미를 만들었다.

로봇 개미는 센서가 있어 개미굴의 각 층에 먹이가 있는 방을 따라 내려가다 더 이상 내려갈 수 없으면 그 자리에서 움직이지 않고 신호를 보낸다.

이 신호로 로봇 개미는 개미굴 각 층을 따라 내려오면서 알게 된 각 방에 저장된 먹이 정보를 윤수한테 알려줄 수 있다.

로봇 개미 개발을 완료한 윤수는 개미굴 탐사를 앞두고 로봇 개미를 테스트 해보기 위해 위 그림의 개미굴에 로봇 개미를 투입했다. (로봇 개미의 수는 각 개미굴의 저장소를 모두 확인할 수 있을 만큼 넣는다.)

다음은 로봇 개미들이 윤수에게 보내준 정보다.

  • KIWI BANANA
  • KIWI APPLE
  • APPLE APPLE
  • APPLE BANANA KIWI

(공백을 기준으로 왼쪽부터 순서대로 로봇 개미가 각 층마다 지나온 방에 있는 먹이 이름을 뜻한다.)

윤수는 로봇 개미들이 보내준 정보를 바탕으로 다음과 같이 개미굴의 구조를 손으로 그려봤다.

APPLE
--APPLE
--BANANA
----KIWI
KIWI
--APPLE
--BANANA

(개미굴의 각 층은 "--" 로 구분을 하였다.

또 같은 층에 여러 개의 방이 있을 때에는 사전 순서가 앞서는 먹이 정보가 먼저 나온다.)

우리의 천재 공학자 윤수는 복잡한 개미굴들을 일일이 손으로 그리기 힘들어 우리에게 그려달라고 부탁했다.

한치 앞도 모르는 험한 이세상 그렇지만 오늘도 행복한 개미들!

행복의 비결을 알기 위해 윤수를 도와 개미굴이 어떤 구조인지 확인해보자.

입력:

첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다.  (1 ≤ N ≤ 1000)

두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이 정보 개수 K가 주어진다. (1 ≤ K ≤ 15)

다음 K개의 입력은 로봇 개미가 왼쪽부터 순서대로 각 층마다 지나온 방에 있는 먹이 정보이며 먹이 이름 길이 t는 (1 ≤ t ≤ 15) 이다. 

출력:

개미굴의 시각화된 구조를 출력하여라.

개미굴의 각 층을 "--" 로 구분하며, 같은 층에 여러개의 방이 있을 때에는 사전 순서가 앞서는 먹이 정보가 먼저 나온다.

풀이방법:

문자열 알고리즘 중 효율성이 가장 좋은 트라이(Trie) 알고리즘을 사용해서 입력받는 문자열을 정리하고, 별도의 탐색없이 지정된 출력형식으로 출력하면 되기 때문에, 재귀를 사용해서 문제에서 요구하는 방식대로 출력하도록 한다.

class Node(object):
    def __init__(self,name,flag=False):
        self.parent = name
        self.terminate = flag
        self.child = {}
        
    def __str__(self):
        return self.parent
        
class Trie(object):
    @classmethod
    def __init__(self):
        self.root = Node(None)
        
    @classmethod
    def insert(self, food):
        currNode = self.root
        for f in food:
            if f not in currNode.child:
                currNode.child[f] = Node(f)
            currNode.terminate = False
            currNode = currNode.child[f]
        currNode.terminate = True
        
    @staticmethod
    def antPrint(curNode,count):
        currList = sorted(list(curNode.child))
        for curr in currList:
            print("-"*count*2,end='')
            print(curNode.child[curr])
            Trie.antPrint(curNode.child[curr],count+1)

n = int(input())
T = Trie()
for _ in range(n):
    list_ = input().split()
    m, foods = list_[0], list_[1:]
    Trie.insert(foods)
Trie.antPrint(Trie.root,0)

 

문제링크:

https://www.acmicpc.net/problem/14725

 

14725번: 개미굴

첫 번째 줄은 로봇 개미가 각 층을 따라 내려오면서 알게 된 먹이의 정보 개수 N개가 주어진다.  (1 ≤ N ≤ 1000) 두 번째 줄부터 N+1 번째 줄까지, 각 줄의 시작은 로봇 개미 한마리가 보내준 먹이

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]14891. 톱니바퀴  (0) 2021.07.01
[BOJ]11725. 트리의 부모 찾기  (0) 2021.06.29
[BOJ]2012. 등수 매기기  (0) 2021.06.17
[BOJ]4690. 완전 세제곱  (0) 2021.06.15
[BOJ]1205. 등수 구하기  (0) 2021.06.10

문제:

숫자의 신은 여러명이 있지만, 그 중에 자연수의 신은 오세준이다. 오세준은 자연수의 신으로 오래오래 살다가 어느 날 음수의 신과 전쟁을 하게 되었다. 오세준은 음수의 신 이다솜을 이기기위해서 큰 숫자를 만들기로 했다.

오세준은 지금 K개의 자연수를 가지고 있다. 오세준은 K개의 수 중에 정확하게 N개의 수를 뽑아내서 그 수를 붙여서 만들 수 있는 수중에 가장 큰 수를 만들고자 한다. 같은 수를 여러 번 이용해도 된다. 단, 모든 수는 적어도 한 번은 이용되어야 한다.

오세준이 현재 가지고 있는 K개의 수가 주어졌을 때, 이 수를 적어도 한 번 이상 이용해서 만들 수 있는 수 중에 가장 큰 수를 출력하는 프로그램을 작성하시오.

예를 들어 지금 오세준이 2, 3, 7 이라는 3개의 수를 가지고 있고, 4개의 수를 뽑아야 한다면, 7732를 만들면 가장 큰 수가 된다.

입력:

첫째 줄에 K와 N이 공백을 사이에 두고 주어진다. K와 N은 각각 1,000보다 작거나 같은 자연수이고, N은 K보다 크거나 같다. 둘째 줄에는 K개의 수가 한 줄에 하나씩 주어진다. 각 수는 1,000,000,000보다 작거나 같은 자연수이다. 이 수는 중복되어 들어올 수 있다. 만약 중복되어서 들어오는 경우에는 각 수가 적어도 입력으로 주어진 만큼 이용되어야 한다는 소리다.

출력:

N개의 수를 뽑아서 연결해서 만들 수 있는 가장 큰 수를 출력한다.

풀이방법:

 가지고 있는 수 K 보다 사용해야 하는 갯수 N이 더 크면 가장 큰 숫자를 여러번 사용하는 것이 큰 수를 만드는데 유리하다. 따라서 가장 큰 수를 찾은 뒤에 N-K개 만큼 배열에 추가적으로 넣어준다.

 

 큰 수를 만들기 위해서는 두 수를 앞 뒤로 붙여보면 된다. 예를 들어 100 과 9 두 숫자가 있다고 했을 때, 큰 수가 무조건 가장 앞으로 오게 한다면 1009를 생성하게 되지만 실제로 큰 수는 9100가 되어야 한다. 따라서 1009 vs 9100과 같이 두 수를 번갈아 붙여보며 큰 수를 찾는 방법을 사용해야 한다. 

 

 따라서 python의 sort의 key 기능을 사용하며, 특수한 함수를 기준으로 정렬을 해야 하기 때문에 cmp_to_key를 사용하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from functools import cmp_to_key
def cmp(x,y):
    if str(x)+str(y)>str(y)+str(x):
        return -1
    else:
        return 1
k, n = map(int,input().split())
numbers = [int(input()) for _ in range(k)]
numbers = sorted(numbers,reverse=True)
 
for _ in range(k,n):
    numbers.append(numbers[0])    
numbers = sorted(numbers,key=cmp_to_key(cmp))
print(*numbers,sep='')
cs

문제링크:

https://www.acmicpc.net/problem/1422

 

1422번: 숫자의 신

첫째 줄에 K와 N이 공백을 사이에 두고 주어진다. K와 N은 각각 1,000보다 작거나 같은 자연수이고, N은 K보다 크거나 같다. 둘째 줄에는 K개의 수가 한 줄에 하나씩 주어진다. 각 수는 1,000,000,000보

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1024. 수열의 합  (0) 2021.06.01
[BOJ]1826. 연료 채우기  (0) 2021.05.27
[BOJ]15686. 치킨 배달  (0) 2021.05.20
[BOJ]2583. 영역 구하기  (0) 2021.05.18
[BOJ]3055. 탈출  (0) 2021.05.11

문제:

알파벳 소문자로 이루어진 단어를 가지고 아래와 같은 과정을 해 보려고 한다.

먼저 단어에서 임의의 두 부분을 골라서 단어를 쪼갠다. 즉, 주어진 단어를 세 개의 더 작은 단어로 나누는 것이다. 각각은 적어도 길이가 1 이상인 단어여야 한다. 이제 이렇게 나눈 세 개의 작은 단어들을 앞뒤를 뒤집고, 이를 다시 원래의 순서대로 합친다.

예를 들어,

  • 단어 : arrested
  • 세 단어로 나누기 : ar / rest / ed
  • 각각 뒤집기 : ra / tser / de
  • 합치기 : ratserde

단어가 주어지면, 이렇게 만들 수 있는 단어 중에서 사전순으로 가장 앞서는 단어를 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에 영어 소문자로 된 단어가 주어진다. 길이는 3 이상 50 이하이다.

출력:

첫째 줄에 구하고자 하는 단어를 출력하면 된다.

풀이방법:

반복문 두 개를 사용해서 주어진 조건대로 하나씩 단어를 만들면서 해당하는 단어가 사전상 먼저 인지 확인하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
string = input()
answer = 'z'*16
for i in range(1,len(string)-1):
    for j in range(i+1,len(string)):
        temp = ''
        for t in range(len(string[:i])-1,-1,-1):
            temp+=string[:i][t]
        for t in range(len(string[i:j])-1,-1,-1):
            temp+=string[i:j][t]
        for t in range(len(string[j:])-1,-1,-1):
            temp+=string[j:][t]
        if answer > temp:
            answer = temp
print(answer)
cs

문제링크:

www.acmicpc.net/problem/1251

 

1251번: 단어 나누기

알파벳 소문자로 이루어진 단어를 가지고 아래와 같은 과정을 해 보려고 한다. 먼저 단어에서 임의의 두 부분을 골라서 단어를 쪼갠다. 즉, 주어진 단어를 세 개의 더 작은 단어로 나누는 것이다

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2621. 카드게임  (0) 2021.02.09
[BOJ]2061. 좋은 암호  (0) 2021.02.04
[BOJ]1715. 카드 정렬하기  (0) 2021.01.28
[BOJ]2529. 부등호  (0) 2021.01.26
[BOJ]2003. 수들의 합 2  (0) 2021.01.19

문제:

워드프로세서 등을 사용하는 도중에 찾기 기능을 이용해 본 일이 있을 것이다. 이 기능을 여러분이 실제로 구현해 보도록 하자.

두 개의 문자열 P와 T에 대해, 문자열 P가 문자열 T 중간에 몇 번, 어느 위치에서 나타나는지 알아내는 문제를 '문자열 매칭'이라고 한다. 워드프로세서의 찾기 기능은 이 문자열 매칭 문제를 풀어주는 기능이라고 할 수 있다. 이때의 P는 패턴이라고 부르고 T는 텍스트라고 부른다.

편의상 T의 길이를 n, P의 길이를 m이라고 하자. 일반적으로, n>= m 이라고 가정해도 무리가 없다. n < m이면 어차피 P는 중간에 나타날 수 없기 때문이다. 또, T의 i번째 문자를 T[i]라고 표현하도록 하자. 그러면 물론, P의 i번째 문자는 P[i]라고 표현된다.

문자열 P가 문자열 T 중간에 나타난다는 것, 즉 문자열 P가 문자열 T와 매칭을 이룬다는 것이 어떤 것인지 아래의 두 예를 통해 알아보자. 위의 예에서 P는, T의 1번 문자에서 시작하는 매칭에 실패했다. T의 7번 문자 T[7]과, P의 7번 문자 P[7]이 서로 다르기 때문이다.

 그러나 아래의 예에서 P는, T의 5번 문자에서 시작하는 매칭에 성공했다. T의 5~11번 문자와 P의 1~7번 문자가 서로 하나씩 대응되기 때문이다.

가장 단순한 방법으로, 존재하는 모든 매칭을 확인한다면, 시간 복잡도가 어떻게 될까? T의 1번 문자에서 시작하는 매칭이 가능한지 알아보기 위해서, T의 1~m번 문자와 P의 1~m번 문자를 비교한다면 최대 m번의 연산이 필요하다. 이 비교들이 끝난 후, T의 2번 문자에서 시작하는 매칭이 가능한지 알아보기 위해서, T의 2~m+1번 문자와 P의 1~m번 문자를 비교한다면 다시 최대 m번의 연산이 수행된다. 매칭은 T의 n-m+1번 문자에서까지 시작할 수 있으므로, 이러한 방식으로 진행한다면 O((n-m+1)*m = O(nm)의 시간복잡도를 갖는 알고리즘이 된다.

 더 좋은 방법은 없을까? 물론 있다. 위의 제시된 예에서, T[7] P[7] 이므로 T의 1번 문자에서 시작하는 매칭이 실패임을 알게 된 순간으로 돌아가자. 이때 우리는 매칭이 실패라는 사실에서, T[7] P[7] 라는 정보만을 얻은 것이 아니다. 오히려 i=1,...,6에 대해 T[i] = P[i]라고 하는 귀중한 정보를 얻지 않았는가? 이 정보를 십분 활용하면, O(n)의 시간 복잡도 내에 문자열 매칭 문제를 풀어내는 알고리즘을 설계할 수 있다.

P 내부에 존재하는 문자열의 반복에 주목하자. P에서 1, 2번 문자 A, B는 5,6번 문자로 반복되어 나타난다. 또, T의 1번 문자에서 시작하는 매칭이 7번 문자에서야 실패했으므로 T의 5,6번 문자도 A,B이다.

따라서 T의 1번 문자에서 시작하는 매칭이 실패한 이후, 그 다음으로 가능한 매칭은 T의 5번 문자에서 시작하는 매칭임을 알 수 있다! 더불어, T의 5~6번 문자는 P의 1~2번 문자와 비교하지 않아도, 서로 같다는 것을 이미 알고 있다! 그러므로 이제는 T의 7번 문자와 P의 3번 문자부터 비교해 나가면 된다.

 이제 이 방법을 일반화 해 보자. T의 i번 문자에서 시작하는 매칭을 검사하던 중 T[i+j-1] ≠ P[j]임을 발견했다고 하자. 이렇게 P의 j번 문자에서 매칭이 실패한 경우, P[1…k] = P[j-k…j-1]을 만족하는 최대의 k(≠j-1)에 대해 T의 i+j-1번 문자와 P의 k+1번 문자부터 비교를 계속해 나가면 된다.

 이 최대의 k를 j에 대한 함수라고 생각하고, 1~m까지의 각 j값에 대해 최대의 k를 미리 계산해 놓으면 편리할 것이다. 이를 전처리 과정이라고 부르며, O(m)에 완료할 수 있다.

 이러한 원리를 이용하여, T와 P가 주어졌을 때, 문자열 매칭 문제를 해결하는 프로그램을 작성하시오.

입력:

첫째 줄에 문자열 T가, 둘째 줄에 문자열 P가 주어진다. 문자열 내에 공백이 포함되어 있을 수도 있음에 유의한다. 물론 공백도 하나의 문자로 인정된다. T와 P의 길이 n, m은 1이상 100만 이하이다.

출력:

첫째 줄에, T 중간에 P가 몇 번 나타나는지를 나타내는 음이 아닌 정수를 출력한다. 둘째 줄에는 P가 나타나는 위치를 차례대로 공백으로 구분해 출력한다. 예컨대, T의 i~i+m-1번 문자와 P의 1~m번 문자가 차례로 일치한다면, i를 출력하는 식이다.

풀이방법:

이 문제에 대한 설명은 KMP 알고리즘에 대한 설명이다. KMP 알고리즘은 bowbowbow.tistory.com/6이 곳에서 정말 잘 설명하고 있는 것 같다. 다음은 해당 링크의 설명을 바탕으로 작성한 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def getpi(p):
    pi=[0]*len(p)
    j = 0
    for i in range(1,len(p)):
        while j > 0  and p[i]!=p[j]:
            j = pi[j-1]
        if p[i]==p[j]:
            j+=1
            pi[i]=j
    return pi
 
def kmp(t,p):
    ans = []
    pi = getpi(p)
    j = 0
    for i in range(len(t)):
        while j>0 and t[i]!=p[j]:
            j=pi[j-1]
        if t[i]==p[j]:
            if j==len(p)-1:
                ans.append(i-len(p)+1)
                j=pi[j]
            else:
                j+=1
    return ans
 
 
= input()
= input()
answer = kmp(t,p)
print(len(answer))
for i in answer:
    print(i+1)
cs
bowbowbow.tistory.com/6

문제링크:

www.acmicpc.net/problem/1786

 

1786번: 찾기

첫째 줄에, T 중간에 P가 몇 번 나타나는지를 나타내는 음이 아닌 정수를 출력한다. 둘째 줄에는 P가 나타나는 위치를 차례대로 공백으로 구분해 출력한다. 예컨대, T의 i~i+m-1번 문자와 P의 1~m

www.acmicpc.net

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1059. 수2  (0) 2020.11.10
[BOJ]10775. 공항  (0) 2020.10.29
[BOJ]19948. 음유시인 영재  (0) 2020.10.15
[BOJ]1644. 소수의 연속합  (0) 2020.10.13
[BOJ]12100. 2048(Easy)  (0) 2020.09.24

문제:

감수성이 뛰어난 음유시인 영재는 일상생활 중에 번뜩 시상이 떠오르곤 한다.

 

하지만 기억력이 좋지 못한 영재는 시상이 떠오르면 그 순간 컴퓨터로 기록해야만 안 까먹는다! 시는 대문자, 소문자 알파벳과 빈칸으로 이루어져 있따. 시상은 매번 훌륭하지만 제목 짓는 센스가 부족한 영재는 시에 나오는 단어들의 첫 글자를 대문자로 바꾼 뒤 순서대로 이어서 제목을 만든다. 만약 시의 내용이 'There is no cow level' 이라면 시의 제목은 'TINCL'이 된다.

 

시도 때도 없이 시를 기록하느라 낡아버린 영재의 키보드는 수명이 얼마 남지 않았다. 앞으로 스페이스 바와 영자판을 누를 수 있는 횟수가 정해져 있어 이를 초과하면 키보드가 수명이 다 하여 어떠한 작업도 하지 못하게 된다. 하나 다행인 점은, 키보드를 쓸 때 같은 문자가 연속으로 나오거나 빈칸이 연속으로 나오는 경우 영재는 자판을 꾹 눌러 한 번만 사용해서 키보드를 좀 더 효율적으로 쓸 수 있다. (A와 a는 다른 문자이므로 'Aa'는 2번의 a자판을 누른 것으로 한다.

 

시의 내용과 시의 제목은 Enter 키로 구분된다. 다향히 Shift 키와 Enter 키는 항상 수명이 무한한 상황이다!

 

음유시인 영재가 이번에 지은 시의 내용과 스페이스 바와 영자판을 누를 수 있는 횟수가 주어졌을 때, 시의 내용과 제목을 모두 기록할 수 있다면 시의 제목을 출력하고, 만약 키보드의 수명이 다 하여 기록을 완벽하게 못 하게 된다면 -1을 출력하여라.

입력:

첫 줄에 시의 내용이 주어진다.

 

둘째 줄에는 스페이스 바의 남은 사용 가능 횟수가 주어진다.

 

셋째 줄에는 대소문자를 구별하지 않고, 26개의 알파벳에 대한 영자판의 남은 사용 가능 횟수가 알파벳순으로 주어진다.

출력:

시의 내용과 제목을 모두 기록할 수 있다면 제목을 출력하여라.

만약 키보드의 수명이 다 하여 기록을 완벽하게 못 하게 되어 작업을 하지 못한다면 -1을 출력하여라.

풀이방법:

주어진 조건대로 구현을 해서 풀면 된다. 이 문제에서 고려해야 하는 조건들은 다음과 같다.

1. 시의 내용과 제목을 모두 작성할 수 있어야 한다.

2. 연속된 문자는 효율적으로 작성을 할 수 있지만 대,소문자 구분은 해야 한다.

 

1을 위해서 두 번 체크 하는 과정이 필요하다. 2를 위해서는 문자열을 비교하는 것은 대소문자로 비교를 하고, 남은 횟수를 줄일 때는 소문자로 바꿔서 진행하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
strings = input().split()
space = int(input())
counts= list(map(int,input().split()))
if len(strings)-1 > space:
    print(-1)
else:
    answer = True
    title = ''
    idx = 0
    while answer and idx < len(strings):
        string = strings[idx]
        i = 0
        while i < len(string):
            if i >= 1 and string[i]==string[i-1]:
                i+=1
                continue
            if counts[ord(string[i].lower())-97]:
                counts[ord(string[i].lower())-97]-=1
            else:
                answer = False
                break
            i+=1
        idx+=1
        if answer:
            title += string[0].upper()
    if answer:
        temp = title.lower()
        i = 0
        while i < len(temp):
            if i >= 1 and temp[i]==temp[i-1]:
                i+=1
                continue
            if counts[ord(temp[i])-97]:
                counts[ord(temp[i])-97]-=1
            else:
                answer = False
                break
            i+=1
        if answer:
            print(title)
        else:
            print(-1)
    else:
        print(-1)
cs

문제링크:

www.acmicpc.net/problem/19948

 

19948번: 음유시인 영재

감수성이 뛰어난 음유시인 영재는 일상생활 중에 번뜩 시상이 떠오르곤 한다. 하지만 기억력이 좋지 못한 영재는 시상이 떠오르면 그 순간 컴퓨터로 기록해야만 안 까먹는다! 시는 대문자, 소��

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]10775. 공항  (0) 2020.10.29
[BOJ]1786. 찾기  (0) 2020.10.27
[BOJ]1644. 소수의 연속합  (0) 2020.10.13
[BOJ]12100. 2048(Easy)  (0) 2020.09.24
[BOJ]1806 부분합  (0) 2020.09.22

문제:

Vigenere cipher이라는 암호화 방법은 암호화하려는 문장(평문)의 단어와 암호화 키를 숫자로 바꾼 다음, 평문의 단어에 해당하는 숫자에 암호 키에 해당하는 숫자를 더하는 방식이다. 이 방법을 변형하여 평문의 단어에 암호화 키에 해당하는 숫자를 빼서 암호화하는 방식을 생각해 보자.

 

예를 들어 암호화 키가 love이고, 암호화할 문장이 "nice day"라면 다음과 같이 암호화가 이루어진다.

제시된 평문의 첫 번째 문자인 'n'은 해당 암호화 키 'l'의 알파벳 순서가 12이므로 알파벳상의 순서에서 'n'보다 12앞의 문자인 'b'로 변형된다.

 

변형된 문자가 'a'이전의 문자가 되면 알파벳 상에서 맨 뒤로 순서를 돌린다. 예를 들면 평문의 세 번째 문자인 'c'는 알파벳 상에서 3번째이고 대응하는 암호화키 'V'는 알파벳 순서 22로 'c'에서 22 앞으로 당기면 'a'보다 훨씬 앞의 문자이어야 하는데, 'a' 앞의 문자가 없으므로 'z'로 돌아가 반복되어 'g'가 된다. 즉 평문의 문자를 암호화키의 문자가 알파벳 상에서 차지하는 순서만큼 앞으로 뺀 것으로 암호화한다.

 

평문의 문자가 공백 문자인 경우는 그 공백 문자를 그대로 출력한다.

이과 같은 암호화를 행하는 프로그램을 작성하시오.

입력:

첫째 줄에 평문이, 둘째 줄에 암호화 키가 주어진다.

평문은 알파벳 소문자와 공백문자(space)로만 구성되며, 암호화 키는 알파벳 소문자만으로 구성된다. 평문의 길이는 공백까지 포함해서 30000자 이하이다.

출력:

첫 번째 줄에 암호문을 출력한다.

풀이방법:

암호화 키와 평문의 차이를 알아야 하므로 ascii코드 값으로 바꿔 주는 ord 함수를 사용한다. 이를 이용해서 암호화 키와 평문의 차이를 구하고 이 값이 0보다 큰지 작은지를 결정한다.

0보다 크다면 해당 차이 값이 96을 더해주도록 한다.(소문자 'a'의 ascii는 97이다.)

만약 작다면 26을 추가로 더해서 뒤에서 부터 이동하도록 한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
sentence=input()
secret=input()
answer=''
for i in range(len(sentence)):
    if sentence[i]==' ':
        answer+=' '
        continue
    diff=ord(sentence[i])-ord(secret[i%len(secret)])
    if diff > 0:
        answer+=chr(diff+96)
    else:
        answer+=chr(diff+26+96)
print(answer)
cs

문제링크:

https://www.acmicpc.net/problem/1718

 

1718번: 암호

Vigenere cipher이라는 암호화 방법은 암호화하려는 문장 (평문)의 단어와 암호화 키를 숫자로 바꾼 다음, 평문의 단어에 해당하는 숫자에 암호 키에 해당하는 숫자를 더하는 방식이다. 이 방법을 변형하여 평문의 단어에 암호화 키에 해당하는 숫자를 빼서 암호화하는 방식을 생각해 보자. 예를 들어 암호화 키가 love이고, 암호화할 문장이 “nice day” 라면 다음과 같이 암호화가 이루어진다. 제시된 평문의 첫 번째 문자인 ‘n’은 해당 암호화 키

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2863. 이게 분수?  (0) 2020.04.16
[BOJ]7785. 회사에 있는 사람  (0) 2020.04.14
[BOJ]1302 베스트셀러  (0) 2020.04.07
[BOJ]1051. 숫자 정사각형  (0) 2020.03.26
[BOJ]2644. 촌수계산  (0) 2020.03.24

+ Recent posts