2018. 8. 12. 01:21ㆍProgramming/Algorithm
문제 - 1158번 조세퍼스 순열
https://www.acmicpc.net/problem/1158
문제
조세퍼스 문제는 다음과 같다.
1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 M(≤ N)이 주어진다. 이제 순서대로 M번째 사람을 제거한다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속된다. 원에서 사람들이 제거되는 순서를 (N, M)-조세퍼스 순열이라고 한다. 예를 들어 (7, 3)-조세퍼스 순열은 <3, 6, 2, 7, 5, 1, 4>이다.
N과 M이 주어지면 (N,M)-조세퍼스 순열을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N과 M이 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ M ≤ N ≤ 5,000)
출력
예제와 같이 조세퍼스 순열을 출력한다.
소스코드
import sys class Queue(): def __init__(self, size): self.maxSize = size self.size = 0 self.arr = ['']*size self.front = -1 self.rear = -1 def enqueue(self, data): if not self.isFull(): self.rear = (self.rear+1) % self.maxSize self.arr[self.rear] = data self.size += 1 def dequeue(self): if not self.isEmpty(): self.front = (self.front + 1) % self.maxSize self.size -= 1 return self.arr[self.front] def isEmpty(self): return self.size == 0 def isFull(self): return self.size == self.maxSize def __bool__(self): return self.isEmpty() a, b = map(int, sys.stdin.readline().strip().split()) people = Queue(a) for i in range(1, a+1): people.enqueue(str(i)) result = '<' while not people.isEmpty(): for i in range(b-1): people.enqueue(people.dequeue()) result += str(people.dequeue()) if not people.isEmpty(): result += ', ' else: result += '>' sys.stdout.write(result)
코멘트
queue를 구현할 때, dequeue를 pop(0)으로 구현했었는데, pop(0)을 사용하면 결국 list 전체가 대이동(?)을 하게 되므로 O(N)의 시간복잡도가 발생한다. 절대로 사용하면 안 된다고 함. 그리고 collections에 deque가 구현되어 있으므로 이걸 사용해도 무난할 듯하다.
이번에 알게 된 사실인데, 파이썬에서 input() 사용은 최대한 피해야 한다. 상당한 시간 차가 난다고. 대용량의 입력이 들어갈 것을 생각하면 stdin.sys.readline()을 쓰는 것을 추천한다. 이 경우엔 뒤의 \n까지 같이 들어가버리니 strip() 혹은 rstrip()을 사용해주면 개행문자가 제외된 입력값을 얻을 수 있다. 단, 이는 공백값까지 전부 날려버리니 상황을 잘 보고 사용할 것.
문제 - 10820번 문자열 분석
https://www.acmicpc.net/problem/10820
문제
문자열 N개가 주어진다. 이 때, 문자열에 포함되어 있는 소문자, 대문자, 숫자, 공백의 개수를 구하는 프로그램을 작성하시오.
각 문자열은 알파벳 소문자, 대문자, 숫자, 공백으로만 이루어져 있다.
입력
첫째 줄부터 N번째 줄까지 문자열이 주어진다. (1 ≤ N ≤ 100) 문자열의 길이는 100을 넘지 않는다.
출력
첫째 줄부터 N번째 줄까지 각각의 문자열에 대해서 소문자, 대문자, 숫자, 공백의 개수를 공백으로 구분해 출력한다.
소스코드
import sys def check_ord(x): global huddle for (i, cmp) in enumerate(huddle): if x >= cmp: return i return 3 result = '' huddle = [ord('a'), ord('A'), ord('0')] for l in sys.stdin: character = [0] * 4 for e in list(l): if e == '\n': break character[check_ord(ord(e))] += 1 character = list(map(str, character)) sys.stdout.write(character[0] + ' ' + character[1] + ' ' + character[2] + ' ' + character[3] + '\n')
코멘트
이상하게 stdin 때문에 시간초과가 자꾸 났던 이상한 문제다. 원래 sys.stdin.readline()으로도 해결이 되었었는데, 고민끝에 sys.stdin()으로 바꾸니 통과가 됐다.
sys.stdin()을 for문과 같이 쓰게 되면, pc에서 실행할 때는 애플리케이션이 강제종료 될 때까지 계속 작동하며 input을 기다리게 된다. 그러나 백준 저지에서는 입력이 끝나자마자 stdin이 닫히므로 프로그램이 정상적으로 종료가 되는 듯하다. 그러나 이 방법이 다른 알고리즘 테스트에서도 먹힐지는 의문이다. 도대체 readline()과 아닌 것의 차이가 뭔지 모르겠다.
문제 1406 - 에디터
https://www.acmicpc.net/problem/1406
문제
한 줄로 된 간단한 에디터를 구현하려고 한다. 이 편집기는 영어 소문자만을 기록할 수 있는 편집기로, 최대 600,000글자까지 입력할 수 있다.
이 편집기에는 '커서'라는 것이 있는데, 커서는 문장의 맨 앞(첫 번째 문자의 왼쪽), 문장의 맨 뒤(마지막 문자의 오른쪽), 또는 문장 중간 임의의 곳(모든 연속된 두 문자 사이)에 위치할 수 있다. 즉 길이가 L인 문자열이 현재 편집기에 입력되어 있으면, 커서가 위치할 수 있는 곳은 L+1가지 경우가 있다.
이 편집기가 지원하는 명령어는 다음과 같다.
L 커서를 왼쪽으로 한 칸 옮김 (커서가 문장의 맨 앞이면 무시됨)
D 커서를 오른쪽으로 한 칸 옮김 (커서가 문장의 맨 뒤이면 무시됨)
B 커서 왼쪽에 있는 문자를 삭제함 (커서가 문장의 맨 앞이면 무시됨)
삭제로 인해 커서는 한 칸 왼쪽으로 이동한 것처럼 나타나지만, 실제로 커서의 오른쪽에 있던 문자는 그대로임
P $ $라는 문자를 커서 왼쪽에 추가함
초기에 편집기에 입력되어 있는 문자열이 주어지고, 그 이후 입력한 명령어가 차례로 주어졌을 때, 모든 명령어를 수행하고 난 후 편집기에 입력되어 있는 문자열을 구하는 프로그램을 작성하시오. 단, 명령어가 수행되기 전에 커서는 문장의 맨 뒤에 위치하고 있다고 한다.
입력
첫째 줄에는 초기에 편집기에 입력되어 있는 문자열이 주어진다. 이 문자열은 영어 소문자로만 이루어져 있으며, 길이는 100,000을 넘지 않는다. 둘째 줄에는 입력할 명령어의 개수를 나타내는 정수 N(1≤N≤500,000)이 주어진다. 셋째 줄부터 N개의 줄에 걸쳐 입력할 명령어가 순서대로 주어진다. 명령어는 위의 네 가지 중 하나의 형태로만 주어진다.
출력
첫째 줄에 모든 명령어를 수행하고 난 후 편집기에 입력되어 있는 문자열을 출력한다.
소스코드
import sys left = [] right = [] word = list(sys.stdin.readline().strip()) num = int(sys.stdin.readline()) left = word for i in range(num): line = sys.stdin.readline().split() if line[0]=='L': if left: right.append(left.pop()) elif line[0]=='P': left.append(line[1]) elif line[0]=='D': if right: left.append(right.pop()) elif line[0]=='B': if left: left.pop() right.reverse() sys.stdout.write(''.join(left) + ''.join(right))
코멘트
input() 사용했다가 시간초과 뜨고 대차게 말아먹었던 첫 케이스다. 원래는 join 사용이나 reverse 사용 때문에 시간 초과가 생겼던 게 아닐까 하는 의문이 들었으나, stdin 부분만 해결하고 나니 바로 통과가 됐다. 물론 join을 안 쓰고 다른 방법을 찾으면 더 빨라질 수는 있을 것이다.