⚙️ 알고리즘/코딩테스트 준비

[Swift/Python] 코테 준비에 알아두면 좋을 사항 / 코드

dev_zoe 2023. 1. 2. 22:19
반응형

Swift, Python 둘다 준비해서 코드가 섞여있습니다.

Swift

✅ 시간초과가 발생할 경우, 아래를 살펴보자.

1) 고차함수를 많이 사용하지는 않았는가? 반복문 안에 고차함수가 들어가있지는 않은가?

2) 배열 대신 튜플을 사용할 수 있는가?

3) 수의 범위가 큰데 반복문을 2-3개씩 돌린다거나 하지는 않는가? -> 시간복잡도 확인

4) 백준이고, 위 문제 모두 아니고 알고리즘이 맞는것 같은데 시간초과가 난다..? 하면 백준 특유의 시간초과 문제일 수 있음.

- 이럴땐 FileIO 클래스를 사용하자. (라이노님 FileIO 클래스 외에도 더 빠른 FileIO가 있다고 함)

-> 하지만 백준에서만 해당 파일을 사용할 일이 있고 코딩테스트에서는 쓸일이 없어서 .. 그냥 파이썬 코드 그대로 옮겨보고 맞는지 체크하고 있다. 

- 혹은 인자를 참조 인자(inout, &)로 넘기는게 더 빠르므로, 이 방법으로 풀 수 있는지도 고려해보자.

5) 형변환은 시간이 오래걸린다.

 

 ✅ 조건문보다 삼항 연산자가 조금 더 시간이 빠른것같다. (이것때문에 시간초과가 해결된 경험이 있음..)

 

Python

✅ 재귀함수를 돌렸는데 런타임 에러나 recursion error가 뜬다면, sys.setrecursionlimit(10**6) 를 맨 위에 써주자.

(재귀의 limit을 늘리는 메소드임)

 

공통

✅ core dumped 에러가 뜨면? ( = 백준 런타임에러)

index가 범위를 벗어났거나, nil 인데 억지로 접근하려고 했거나, 수의 범위가 자료형의 범위를 넘어설 때, 자료형 변환 시 변환을 할 수 없을 때, 0으로 나눈다거나 할 때

 

✅ 소수를 다루는 문제의 경우, 컴퓨터가 부동소수점으로 인해 실수를 정확히 표현하지 못할 수 있으니 이때는 round를 통해 반올림해주자.

 

✅ 인덱스가 범위를 넘어가지 않게 하려면, 나머지(%) 연산을 활용한다. (예를들어 26까지인데 27을 넘어간다고 하면 26으로 나누면 1이니까 절대 26를 초과하지 않음)

 

데이터의 범위가 큰데(입력크기가 큰데) 탐색을 해야한다면 딕셔너리나 세트를 활용하자. (배열은 O(n)인데 해시는 O(1)임)

 

알아두면 좋을 사항이나 코드

문자열

✅ 애너그램 판별 (순서를 바꿔서 다른 문자로 만들 수 있는지)

두 문자열을 정렬한 다음, 정렬한 문자열이 서로 같으면 애너그램, 아니면 애너그램이 아니다.

 

✅ 팰린드롬 X -> 팰린드롬 만들기

1) 각 문자의 개수가 홀수인 문자가 2개 이상이면? -> 팰린드롬 불가

2) 홀수인 문자열 중 하나는 중간에 와야하므로, mid 라는 변수에 저장

3) 짝수개인 문자를 자기 자신의 개수의 절반만큼 문자열에 더함

4) 다 더한 문자열에 중간 문자를 더하고, 다 더한 문자열의 역순을 더하면 팰린드롬 완성

from collections import Counter

str = input()
counter = Counter(str)

mid = ''
oddCount = 0

for k, v in list(counter.items()):
  if v%2 != 0:
    mid = k
    oddCount += 1

  if oddCount >= 2:
    print("팰린드롬 불가")
    exit(0)

result = ''

arr = sorted(counter.items())
for k, v in arr:
  result += k * (v//2)

result += mid + result[::-1]
print(result)

 

✅ 아스키코드 (알파벳 순회) 활용 문제

현재 알파벳이 a나 A로부터 얼마나 떨어져있는지? -> (ord(현재 알파벳) - ord('a')/ord('A')) % 26

그만큼 떨어져있는 알파벳을 구하려면? -> 위에 ord('a') 혹은 ord('A') 추가

 

소문자와 대문자의 아스키코드는 서로 다르므로, 구분해서 사용해야함

 

n진수

✅ 정수(10진수) --> n진수 문자열로 변경하기

func radixChange(_ num: Int, _ radix: Int) -> String {
	if num == 0 {
    	return "0"
    }
    
    //16진수라면 10부터는 A ~ F 알파벳 추가
    // var code = ["A", "B", "C", "D", "E", "F"]
    
    var nums: [String] = []
    var num = num
    var remain = 0
    
    while num > 0 {
    	remain = num%radix   // Python에서는 divmod라는 기능으로 몫과 나머지를 한번에 구할 수 있음
        num /= radix
        nums.append(String(remain))   // 변환하려는 진법으로 나눈 나머지를 차곡차곡 문자열로 저장햇다가
    }
    
    return Array(nums.reversed()).joined()   // 뒤집어서 출력
 }

- Swift 진법 변경: String(num, radix: 진수) --> 2부터 36까지의 진수 변환 지원 , 시간초과 발생 시 위 코드 사용 필요

- Python 진법 변경: 2진수/bin(), 8진수/oct(), 16진수/hex() --> 0b나 0x 를 제거할 필요가 있고, 이외의 진수 변환 필요 시 위 코드 사용 필요

 

✅ n진수 문자열 --> 정수(10진수) 변환

- Swift --> Int(String, radix: n)!

- Python --> int(string, n)

 

기타

✅ 최대공약수, 최소 공배수

Swift

// 최대공약수
func GCD(_ a: Int, _ b: Int) -> Int {
    let mod = a % b
    return 0 == mod ? min(a, b) : GCD(b, mod)
}

// 최소공배수
func LCM(_ a: Int, _ b: Int) -> Int {
    return a * b / GCD(a, b)
}

 

Python

import math

math.gcd(a, b)

math.lcm(a, b)

 

✅ 배열 회전

2차원 (시계방향 90도)

func rotation90right(_ array:[[Int]]) -> [[Int]] { //90도 회전 함수
    let n = array.count
    var new_array = Array(repeating: Array(repeating: 0, count: n), count: n)
    for i in 0...n-1 {
        for j in 0...n-1 {
            new_array[j][n-i-1] = array[i][j]
        }
    }
    return new_array
}

1차원 (시계방향 / 반시계 방향) ⭐

- 인덱스 회전

-> 특히 주의할 점은 Swift는 음수 인덱스를 지원하지 않으므로, 반드시 음수일 경우 현재 리스트의 길이만큼 더하는 과정이 필요하다.

  index = (index+move_count) % list.count //move_count 만큼 이동하기

  if index < 0 { //swift는 음수 인덱스 처리를 못하므로 현재 q의 count만큼 더해줘야함
    index += list.count
  }

- 배열 회전

    if index > 0 { //오른쪽으로 index 만큼 밀기 (양수)
        for _ in 0..<index - 1 {
            q.insert(q.removeLast(), at: 0)
        }
    } else { //왼쪽으로 index만큼 밀기 (음수)
        for _ in 0..<index * -1 {
        	q.append(q.removeFirst())
        }
    }

 

(Python)

1) deque의 rotate를 사용하여 회전 가능 (시간복잡도 O(n))

- 음수 : 반시계 방향 / 양수 : 시계방향 n번 회전

>>> from collections import deque
>>> test = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> test = deque(test)
>>> test.rotate(2) 
>>> result = list(test)
>>> result
[8, 9, 1, 2, 3, 4, 5, 6, 7]

 

2) (정수일때) 수학적으로 접근하여 배열 회전의 시간을 줄이는 코드 (O(1))

 

- 1234 --> 왼쪽 회전 --> 2341

n // 1000 + (n % 1000) * 10

 

- 1234 --> 오른쪽 회전 --> 4123

n // 10 + (n % 10) * 1000

 

✅ 제곱수 판별

func solution(_ n:Int) -> Int {
    let root = Int(sqrt(Double(n))) //sqrt : 제곱근
    return root * root == n ? 1:2
}

 

✅ 조합, 순열 ⭐

 

Swift

https://devyul.tistory.com/entry/Swift-%EC%A1%B0%ED%95%A9combination-%EC%88%9C%EC%97%B4permutation

 

Python

from itertools import combinations/combinations

list(combinations/permuations(data, 3))   // 리스트에서 3개를 선택하는 조합/순열

 

- 조합 응용 관련해서 좋은 문제 : https://www.acmicpc.net/problem/9375

 

✅ 소수 판별

 

1) 에라토스테네스의 체 -> 시간복잡도 O(NloglogN))  

import math

n = 1000
arr = [True] * (n+1) # 소수인지 여부를 담을 배열 -> 처음엔 다 소수로 가정

for i in range(2, int(math.sqrt(n))+1):   # int(n**0.5) + 1
	if arr[i]:
		# i를 제외한 i의 모든 배수에 False 표시 (무언가의 배수이면 소수가 아님)
		j = 2
		while (i*j) <= n:
			arr[i*j] = False
			j += 1

for i in range(2, n+1): # 모든 소수 출력
	if arr[i]:   # 위 로직을 거쳐서 True인거라는거는 소수라는 의미임
		print(i)

단, 배열을 n 크기만큼 초기화해야해서 메모리가 많이 필요하여 n의 범위와 무관하게 사용할 시 메모리 초과 오류를 볼 수도 있다.

보통 N이 1,000,000 이내로 주어지는 경우에 사용

 

2) 일반 방법 -> 시간복잡도 O(X^1/2)

import math

def isPrimeNumber(x):
    if n <= 1:
        return False
    elif n <= 3:
        return True
    else:
        for i in range(2, int(math.sqrt(x)) + 1):  # = for i in range(2, int(x**0.5) + 1)
            if x % i == 0:   # 자기가 아닌 수인데 나눠지는 수가 있다면, 소수가 아님
                return False
        return True

 

✅ 구간 합 빠르게 계산하기 

let n = 5
let data = [10, 20, 30, 40, 50]

var sum_value = 0
var prefix_sum = [0]

for i in data {
	sum_value += i
    prefix_sum.append(sum_value)
}

//구간 합 계산 -> 세번째 수부터 네번째 수까지
left = 3
right = 4
print(prefix_sum[right] - prefix_sum[left-1])

 

+ 기타 도움되는 블로그 글들 (감사합니다!)

https://velog.io/@eunsung-dev/Swift%EB%A1%9C-%EC%BD%94%EB%94%A9-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A4%80%EB%B9%84%ED%95%98%EB%A9%B4%EC%84%9C-%EB%8F%84%EC%9B%80-%EB%90%A0%EB%A7%8C%ED%95%9C-%EC%9E%A1%EB%8B%A4%ED%95%9C-%EC%A7%80%EC%8B%9D

https://velog.io/@leedool3003/iOS-swift-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%97%90-%ED%95%84%EC%9A%94%ED%95%9C-Tip-%EC%A0%95%EB%A6%AC

반응형