오늘은 밀러 - 라빈 , 폴라드 - 로의 하루가 될 것 같은 느낌.

골드 5였던 문제였고, 주의해야할 점이 상당히 많았던 문제.

 

아래는 밀러-라빈 / 폴라드-로때 작성한 코드

import sys
import random
from collections import defaultdict
import math

sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline

def power(x, y, p):
    res = 1
    x = x % p
    while y > 0:
        if y & 1:
            res = (res * x) % p
        y = y >> 1
        x = (x * x) % p
    return res

def gcd(a, b):
    if a < b:
        a, b = b, a
    while b != 0:
        r = a % b
        a = b
        b = r
    return a

def miller_rabin(n, a):
    r = 0
    d = n - 1
    while d % 2 == 0:
        r += 1
        d = d // 2

    x = power(a, d, n)
    if x == 1 or x == n - 1:
        return True

    for i in range(r - 1):
        x = power(x, 2, n)
        if x == n - 1:
            return True
    return False

def is_prime(n):
    alist = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
    if n == 1:
        return False
    if n == 2 or n == 3:
        return True
    if n % 2 == 0:
        return False
    for a in alist:
        if n == a:
            return True
        if not miller_rabin(n, a):
            return False
    return True


def pollardRho(n):
    if is_prime(n):
        return n

    if n == 1:
        return 1

    if n % 2 == 0:
        return 2

    x = random.randrange(2, n)
    y = x
    c = random.randrange(1, n)
    d = 1
    while d == 1:
        x = ((x ** 2 % n) + c + n) % n
        y = ((y ** 2 % n) + c + n) % n
        y = ((y ** 2 % n) + c + n) % n
        d = gcd(abs(x - y), n)
        if d == n:
            return pollardRho(n)
    if is_prime(d):
        return d
    else:
        return pollardRho(d)

 

 

 

아래 부분이 해당 알고리즘을 활용한 본 문제의 실제 코드가 되겠다.

 

while True:
    x = int(input())
    if x == 0:
        break

    prime = defaultdict(int)
    y = abs(x)
    while y > 1:
        divisor = pollardRho(y)
        prime[divisor] += 1
        y = y // divisor

    degree = list(set(prime.values()))
    degree_gcd = math.gcd(*degree)

    for deg in degree:
        deg //= degree_gcd

    if x < 0:
        if degree_gcd % 2 == 0:
            while degree_gcd % 2 == 0:
                degree_gcd //= 2
    
    print(degree_gcd)
import sys
import random
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline

def power(x, y, p):
    res = 1
    x = x % p
    while y > 0:
        if y & 1:
            res = (res * x) % p
        y = y >> 1
        x = (x * x) % p
    return res

def gcd(a, b):
    if a < b:
        a, b = b, a
    while b != 0:
        r = a % b
        a = b
        b = r
    return a

def miller_rabin(n, a):
    r = 0
    d = n - 1
    while d % 2 == 0:
        r += 1
        d = d // 2

    x = power(a, d, n)
    if x == 1 or x == n - 1:
        return True

    for i in range(r - 1):
        x = power(x, 2, n)
        if x == n - 1:
            return True
    return False


def is_prime(n):
    alist = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
    if n == 1:
        return False
    if n == 2 or n == 3:
        return True
    if n % 2 == 0:
        return False
    for a in alist:
        if n == a:
            return True
        if not miller_rabin(n, a):
            return False
    return True


def pollardRho(n):
    if is_prime(n):
        return n
    if n == 1:
        return 1
    if n % 2 == 0:
        return 2
    x = random.randrange(2, n)
    y = x
    c = random.randrange(1, n)
    d = 1
    while d == 1:
        x = ((x ** 2 % n) + c + n) % n
        y = ((y ** 2 % n) + c + n) % n
        y = ((y ** 2 % n) + c + n) % n
        d = gcd(abs(x - y), n)
        if d == n:
            return pollardRho(n)
    if is_prime(d):
        return d
    else:
        return pollardRho(d)

def jud_prime(p): #단순히 소수 측정만 하는 것
    divisor_prime = []
    while p > 1:
        divisor = pollardRho(p)
        divisor_prime.append(divisor)
        p //= divisor

    if len(divisor_prime) == 1: #소수인 경우
        return True
    else:
        return False

def f(a, n, p):
    if n == 1:
        return a % p
    if n % 2 == 0:
        return (f(a, n // 2, p) ** 2) % p
    else:
        return (a * (f(a,n // 2, p) ** 2)) % p

def solution(p, a):
    # p가 소수라면, 문제의 조건을 만족하지 않으므로, no를 반환
    if jud_prime(p) == True:
        return 'no'

    # p가 소수가 아니라면?
    if f(a, p, p) == a:
        return 'yes'
    else:
        return 'no'

while True:
    p, a = map(int,input().split())
    if p == 0 and a == 0:
        break

    print(solution(p, a))

 

 

폴라드- 로 / 밀러 - 라빈을 활용한 소인수분해 및 소수 판정

그리고 분할정복을 활용한 코드

 

 

주어진 문제는 위와 같다.

이 문제를 풀면서 중요한 점이 2가지 있는데, 이것을 생각해보자.

 

첫번째로, $R(n,m)$을 계산함에 있어 $if m > n$ then $R(n,m) = 0$ 이라는 점이겠다.

두번째로, 문제에서 주어진 식인 $R(n+1, m+1) = (R(n,m) \cdot R(n,m +1) + 1) / R(n-1, m)$

 

여기서, $R(n,m)$가 사실은 다음과 같은 모양을 하고 있다고 가정해보자. 

$$ R(n, m) = (n - m) \cdot m + 1$$

 

이러한 식을 세웠다면 먼저 검증해야할 것이 있다. 소위 말하는 수학적 귀납법이 되겠다.

i) 초기 조건에서 성립하는지?

ii) 임의의 상황에서도 성립하는지?

 

초기조건인 $n = 0, m = 0$에서는 자명하게 성립하는 것을 알 수 있다.

그렇다면 임의의 $n, m$에 대해서는 어떨까?

 

여기서는 일반성을 잃지 않고, $n-1 >= m$ 이라고 가정하자.  만약, $n - 1 < m$이라는 것은, $n < m + 1$ 꼴인데,

첫번째 조건에서 $m > n$이라면 $R(n,m) = 0$이라는 것을 알 수 있고, 해당 되는 케이스는 $n = m$ 뿐인데, 이건 1로 자명하기 때문.

 

그렇다면, 식을 실제로 검증해보자. $$\frac{1 + R(n,m) \cdot R(n,m +1)}{R(n-1, m)}  = \frac{1 + ((n - m)m + 1) \cdot ((n-m-1) \cdot (m+1) + 1)} {(n-1-m)\cdot m  + 1} $$

 

여기서, 분모인 $(n-1-m)\cdot m  + 1$를 $X$로 치환하게 되면, 분자의 부분은 다음과 같이 나타낼 수 있다

\[
\begin{aligned}
    &((n - m)m + 1) \cdot ((n-m-1) \cdot (m+1) + 1) \\
    &= (X + m)(X + n - m - 1) + 1 \\
    &= X^2 + (n - 1)X + m(n-m-1) + 1 \\
    &= X^2 + (n - 1)X + (X-1) + 1 \\
    &= X^2 + nX.
\end{aligned}
\]

그러므로, $$\frac{X^2 + nX}{X} = X + n =n(m+1) -m (m+1) + 1 = (n-m) (m+1) + 1 = R(n+1, m+1)$$

이렇게 나타내어지는 것을 알 수 있겠다.

 

위의 과정을 통해, 수학적 귀납법이 허용된다는 것을 알았으니, 해답 코드는 다음과 같이 간단하게 쓰일 수 있겠다.

 

import sys
input = sys.stdin.readline

T = int(input())
for _ in range (T):
    n, m = map(int,input().split())
    print((n-m) * m + 1)

 

 

 

 

 

 

 

도중까지 읽다가, 아 이거 위상정렬이군

 

하고 있었는데, 가능하면 쉬운 문제부터 풀어야한다는 점이 상당히 핵심적

그럼에도 불구하고 어렵지 않은 이유는, 

 

topological sorting에서 indegree가 0이 되는 것들을 우선적으로 넣고, 그 이후에 node를 방문하며 하나씩 간선을 제거해나가는 (indegree를 1씩 줄이는 방식)을 취하는 것인데 이 부분에서 Indegree가 0 이 되는 것을 heap에다가 넣어두면 되겠다.

 

Heap은 항상 최솟값을 뱉어내기 때문에, 3번 조건인 쉬운 문제부터 풀어야 한다를 풀기 최적화되어있는 알고리즘이겠다.

반대로, 어려운 문제부터 풀어야한다라면, 최대힙 (즉, 마이너스를 붙여서 저장하는 것)부터 활용하면 되겠다.

 

아래는 답안 코드

import sys
import heapq

N, M = map(int,input().split())
indegree = [0 for _ in range (N+1)]
path = [[] for _ in range (N+1)]

for _ in range (M):
    a,b = map(int,input().split())
    indegree[b] += 1
    path[a].append(b)
    
prior_solving = []
for i in range (1, N+1):
    if indegree[i] == 0:
        heapq.heappush(prior_solving,i)

answer = []
while prior_solving:
    x = heapq.heappop(prior_solving)
    answer.append(x)
    
    for y in path[x]:
        indegree[y] -= 1
        if indegree[y] == 0:
            heapq.heappush(prior_solving,y)
            
print(*answer)

 

이전에 풀었던 예쁜 수 였던가? 굉장히 유사했던 것 같다.

결국은 Dynamic Programming이 얼만큼 이전 정보를 유용하게 활용할 것인지? 를 묻는 상황이므로,

이 부분을 잘 컨트롤 할 필요가 있겠다.

 

 

이 문제 같은 경우에는, 2가지 스텝으로 나눠서 풀면 된다.

 

첫번째로, 사면체로서 가능한 패턴인 숫자들을 구해주는 것이 되겠다.

이를 구하기 위해서는 각 step의 삼각형을 구성하기에는 몇개의 대포알이 필요한지 알아낼 필요가 있겠다.

 

이는 생각보다 쉽다. $n$번째 단의 삼각형을 만드는 것에 필요한 대포알은 $n(n + 1) / 2$개이라는 것을 쉽게 알 수 있다.

1, 3, 6, 10... 이런 Typical한 패턴을 주는 것에 유의하자.

 

그렇다면 사면체는 어떠한가? 1~n번째 단을 만드는데 필요한 대포알을 전부 합치면 되겠다.

수식으로 나타내게 된다면, 

$$\sum_{i =1}^n \frac{n(n + 1)}{2}  = \frac{1}{2} \sum_{i=1}^n n(n+1) = \frac{1}{2} (\sum_{i=1}^n n^2  + \sum_{i=1}^n n)$$

$$ = \frac{n(n+1)(2n +1)} {12} + \frac{n(n+1)}{4} = \frac{n(n + 1)(2n+1) + 3n(n+1)}{12} $$

$$= \frac{2n(n+1)(n+2)}{12} = \frac{n(n+1)(n+2)}{6}$$

이런 식으로 나올수는 있겠지만 .... 사실은 프로그래밍 안에서는 그냥 리스트 2개 만들어서 하는 편이 훨씬 낫다 ...

 

두번째 단계는, 결국 최소 step을 구하고자 하는 상황이므로, dp 리스트를 만들어 두고, 하나씩 추가하는 방식으로 진행하면 좋겠다.

비슷한 유형으로, 예쁜수가 있겠다. (https://pjw9777.tistory.com/102)

 

import sys
input = sys.stdin.readline

N = int(input())
bullet, bullet_sum = [1], [1]
cnt = 2

while bullet_sum[-1] <= N:
    bullet.append((cnt * (cnt + 1)) // 2)
    bullet_sum.append(bullet_sum[-1] + bullet[-1])
    cnt += 1

dp = [N for _ in range (0, N + 1)]

for i in range (0, len(bullet_sum)-1):
    dp[bullet_sum[i]] = 1
    for j in range (bullet_sum[i] + 1, N + 1):
        dp[j] = min(dp[j - bullet_sum[i]] + 1, dp[j])

print(dp[-1])

 

 

 

 

처음에는 그냥 python으로 풀었는데, 이후 Pypy로 푸니 어마무시하게 줄어들은 것을 확인할 수 있었다.

대신 메모리는 많이 잡아 먹었지만 .....

'Algorithm' 카테고리의 다른 글

[BOJ, 백준] 2676 라스칼 삼각형 Python  (0) 2024.12.23
[BOJ, 백준] 1766 문제집 Python  (1) 2024.12.15
[백준, BOJ] 2467 용액 Python  (0) 2024.12.11
Leet Code - Medium 부수기  (1) 2024.11.21
[BOJ, 백준] 14567 선수과목 Python  (0) 2024.10.18

 

 

풀어놓고서도 오늘의 한심함이 가득가득 몰려왔었다.

BOJ 게시판에 쓰려다가 말았지만 (스스로의 안일함과 멍청함에 대하여) 여기서라도 남긴다면, 

주어지는 수의 범위를 잘 볼 필요가 있다. 정말 잘 볼 필요가 있다.

(여기서만 한 4번 터졌다)

 

저 같은 경우에는 투포인터로 풀었습니다. 투 포인터라던지 이분탐색 같은 경우에는, 크기 순서대로 정렬 되어있어야한다

가 전제인데요, 이 문제 같은 경우에는 겹치는 수치도 없거니와 이미 크기 순으로 정렬되어 있다는 점이 문제 풀기 딱 좋은 환경인 것 같네요.

 

정답 코드는 다음과 같습니다.

 

import sys
input = sys.stdin.readline

N = int(input())
liquid = list(map(int,input().split()))

mix_val = int(1e9) * 2
ans_l, ans_r = 0, N-1

l, r = 0, N-1
while l < r:
    val = liquid[l] + liquid[r]
    if abs(val) < mix_val:
        ans_l, ans_r = l, r
        mix_val = abs(val)
        if val == 0:
            break
    if val <= 0:
        l += 1
    else:
        r -= 1
print(liquid[ans_l], liquid[ans_r])

'Algorithm' 카테고리의 다른 글

[BOJ, 백준] 1766 문제집 Python  (1) 2024.12.15
[BOJ, 백준] 1660 캡틴 이다솜 Python  (0) 2024.12.11
Leet Code - Medium 부수기  (1) 2024.11.21
[BOJ, 백준] 14567 선수과목 Python  (0) 2024.10.18
[BOJ, 백준] 25958 예쁜수 Python  (1) 2024.10.15

 

코딩테스트를 준비하다보니 ... Medium을 제안 받았던만큼 스스로 풀었던 문제 복기를 좀 해볼까 한다.

혹시나 싶어 코드를 보고 싶으신 분이라면 문제 번호나 타이틀로 검색하시면 좋을 것 같습니다.

 

238. Product of Array Except self

풀이시간은 박살났지만 ..... 아이디어로는 dp 2개 (left_product, right_product) 2개 만들어서 교차 곱셈

 

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        dp_left = [1 for _ in range (0, len(nums) + 1)]
        dp_right = [1 for _ in range (0, len(nums) + 1)]
        for i in range (1, len(nums) + 1):
            dp_left[i] *= (dp_left[i-1] * nums[i-1])
            dp_right[-1-i] *= (dp_right[-i] * nums[-i])
        answer = []

 

347. Top K Frequent Elements

아이디어로는 defaultdict으로 나타낸 뒤에, items을 활용해 tuple 형태로 이를 저장 한다

그 뒤에는 빈도수로 정렬하면 okay

 

from collections import defaultdict
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        cnt = defaultdict(int)
        for num in nums:
            cnt[num] += 1
        
        frequent = []
        for x, y in cnt.items():
            frequent.append([x,y])

        frequent.sort(key = lambda x: (-x[1], x[0]))
        answer = []
        for num_tuple in frequent:
            answer.append(num_tuple[0])
        return answer[:k]

 

 

454. 4 Sum II

O(N^2)이냐, O(N^3)인가가 차이가 나오게 된다. (덧셈의 tuple을 어떻게 짜느냐에 따라)

 

from collections import defaultdict
class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:

        sum_12 = defaultdict(int)
        sum_34 = defaultdict(int)
        for num1 in nums1:
            for num2 in nums2:
                sum_12[num1 + num2] += 1
        
        for num3 in nums3:
            for num4 in nums4:
                sum_34[num3 + num4] += 1
        
        cnt = 0
        for x, y in sum_12.items():
            cnt += y * sum_34[(-1) * x]
        
        return cnt

 

 

53. Maximum Subarray

합이 최대인 subarray를 찾아내야한다.

이름이 뭐였더라. 카데인 알고리즘이었던 것 같다. curr_max에 현재까지 최대인 것 저장해나가면서 풀면 된다.

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return nums[0]
        curr_max = 0
        answer = -int(1e9)

        for num in nums:
            curr_max = max(num, curr_max + num)
            answer = max(answer, curr_max)
        return answer

 

 

54. Spiral Matrix

주어진 2차원 matrix에서 외곽을 따라서 숫자를 보관해주면 된다. 

총 네방향으로 움직일 수 있고, 방향을 바꾸는 것은 

i) 행렬의 끝에 도달했을 때 

ii) 현재 방향으로 앞으로 한번 더 나갔을 때, 이미 방문했던 곳에 도착할 때

이때 방향을 바꿔주면 되겠다

 

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        movement_x = [0,1,0,-1]
        movement_y = [1,0,-1,0]
        visited = [[False for _ in range (0, len(matrix[0]))] for _ in range (0, len(matrix))]
        cnt, direction = 0,0
        answer = []
        x, y = 0, 0
        while cnt != len(matrix[0]) * len(matrix):
            answer.append(matrix[x][y])
            print(matrix[x][y])
            visited[x][y] = True
            nx, ny = x + movement_x[direction % 4], y + movement_y[direction % 4]
            if (0 > nx or nx >= len(matrix) or 0 > ny or ny >= len(matrix[0])) or (visited[nx][ny] == True):
                direction += 1
                nx, ny = x + movement_x[direction % 4], y + movement_y[direction % 4]
            x, y = nx, ny
            cnt += 1
        return answer

 

 

48. Rotate Image

 

주어진 정사각행렬을 오른쪽으로 한바퀴 돌리면 되는건데, 이건 두스텝으로 풀어낼 수 있다.

첫번째로 Transpose를 해서 행렬을 전치시킨다.

두번째로 행을 고정시킨 뒤, 열을 반전 시키는 방식으로 풀면 되겠다.

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        #처음에는 transpose
        n = len(matrix)
        for i in range (0, n):
            for j in range (i, n):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        
        #전후 반전
        for i in range (0, n):
            for j in range (0, n // 2):
                matrix[i][j], matrix[i][n-1-j] = matrix[i][n-1-j], matrix[i][j]
        print(matrix)

 

 

 

78. Subsets

주어진 집합의 모든 부분집합을 구해주면 되겠다.

Backtracking의 typical한 문제가 되겠다. 항상 stack에서 pop 해주는 것을 잊지말자.

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = []
        curr_subset = []

        def backtracking(n):
            result.append(curr_subset.copy())
            for i in range(n, len(nums)):
                curr_subset.append(nums[i])
                backtracking(i+1)
                curr_subset.pop()
        
        backtracking(0)
        return result

 

 

46. Permutations

또 항상 나오는 backtracking.

이럴때는 방문처리를 꼭 해주는 것이 현명하다.

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:

        result = []
        curr_subset = []
        visited = [False for _ in range (0, len(nums))]
        
        def backtracking(n):
            
            if n == len(nums):
                result.append(curr_subset.copy())
                return
            else:
                for i in range (0, len(nums)):
                    if visited[i] == False:
                        visited[i] = True
                        curr_subset.append(nums[i])
                        backtracking(n + 1)
                        curr_subset.pop()
                        visited[i] = False
        backtracking(0)
        return result

 

 

215. Kth Largest Element in an array

Array에서 K번째로 큰 원소를 찾으면 된다 굉장히 직관적인 문제.

Heap을 사용하면 비교적 간단하게 풀 수 있다. 처음에 K사이즈짜리 heap을 준비해주고, 새로운 것을 넣느냐 마느냐 식으로 진행하면 되겠다.

class Solution:
    import heapq
    def findKthLargest(self, nums: List[int], k: int) -> int:
        x = nums[:k]
        heapq.heapify(x)
        for i in range (k, len(nums)):
            y = heapq.heappop(x)
            if y >= nums[i]:
                heapq.heappush(x, y)
            else:
                heapq.heappush(x, nums[i])
        return heapq.heappop(x)

 

 

49. Group Anagrams

같은 스펠링이 들어간 단어들을 하나로 그룹으로 묶으면 되겠다.

defaultdict으로 묶어주는 것이 가장 간편하다고 느껴졌다.

 

from collections import defaultdict
class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        word_list = defaultdict(list)
        for word in strs:
            spelling = []
            for i in range (len(word)):
                spelling.append(word[i])
            spelling.sort()
            spelling = tuple(spelling)
            word_list[spelling].append(word)
        return list(word_list.values())

 

 

200. Number of Islands

 

BFS / DFS로 정평이 난... 문제들이다.

from collections import deque
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        #bfs
        n, m = len(grid), len(grid[0])
        visited = [[False for _ in range (m)] for _ in range(n)]
        cnt = 0
        dx, dy = [0, 0, 1, -1], [1, -1, 0, 0]
        for i in range (n):
            for j in range (m):
                if grid[i][j] == "1" and visited[i][j] == False:
                    cnt += 1
                    lands = deque()
                    lands.append([i,j])
                    while lands:
                        land = lands.popleft()
                        x, y = land[0], land[1]
                        if visited[x][y] == False:
                            visited[x][y] = True
                            for k in range (0, 4):
                                nx, ny = x + dx[k], y + dy[k]
                                if 0 <= nx < n and 0 <= ny < m and visited[nx][ny] == False and grid[nx][ny] == "1":

                                    lands.appendleft([nx, ny])
        return cnt

 

 

 

17. Letter combinations of a Phone number

자주 나오는 백트래킹 문제...였는데, 이 경우에는 corr_sym에 핸드폰 자판에 해당되는 것으로 만들어두었다.

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        corr_sym = [[], [], ['a', "b", "c"], ["d", "e", "f"],
        ["g", "h", "i"], ["j", "k", "l"], ["m", "n", "o"], ["p", "q", "r", "s"], ["t", "u", "v"],   
        ["w", "x", "y","z"]]
        answer = []
        curr_word = []
        if digits == "":
            return []
        def backtracking(n):
            if n == len(digits):
                word = "".join(string for string in curr_word)
                answer.append(word)
                return
            for spelling in corr_sym[int(digits[n])]:
                curr_word.append(spelling)
                backtracking(n+1)
                curr_word.pop()
        backtracking(0)
        return answer

 

 

287. Find the Duplicate Number

중복이 되는 숫자가 뭐냐? 라고 물어보는 상황이었기에 defaultdict으로 카운팅

 

from collections import defaultdict
class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        check = defaultdict(int)
        for num in nums:
            if check[num] == 0:
                check[num] = 1
            else:
                return num

 

 

300. Longest Increasing Subsequence

최장 증가 수열 (Strictly한)을 찾는 것이다.

1차원 dp문제로 기억하고 있다.

이전 값들과 비교해나가면서 큰지 어떤지 계산해주면 되겠다.

그래서 거의 O(N**2) 정도로 되는 것으로 받아들일 수 있다. (아마 N**2보다는 작겠지만)

 

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        #Strictly increasing
        n = len(nums)
        dp = [1 for _ in range (n)]
        max_length = 1
        for i in range (0, n):
            for j in range (0, i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j] + 1)
                    max_length = max(max_length, dp[i])
        return max_length

 

22. Generate Parenthese

 

마치 적절한 괄호 갯수를 카운팅해보세요. or  구현해보세요.

같은 문제입니다. 백트래킹 / 브루트포스에 가까운 문제라고 생각되네요.

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        #원래 있던 거에 씌우거나 / 2개를 합치거나
        dp = [[] for _ in range (n + 1)]
        dp[1] = ["()"]
        for i in range (2, n + 1):
            for parent in dp[i-1]:
                dp[i].append("(" + parent + ")")
            for j in range (1, i // 2 + 1):
                for parent1 in dp[i-j]:
                    for parent2 in dp[j]:
                        dp[i].append(parent1 + parent2)
                        dp[i].append(parent2 + parent1)
            dp[i] = list(set(dp[i]))
        return dp[-1]

 

 

210. Course Schedule II

 

아마 위상 정렬 그래프였던가? 그런 이름이었던 것으로 기억한다.

그래프의 끝점 (indegree가 0인 점)부터 시작해주면서, indegree가 0이 되면 deq에 넣어주는 형식이다.

from collections import deque
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        answer = []
        ind = [0 for _ in range (0, numCourses)]
        course = [[] for _ in range (0, numCourses)]
        for pre in prerequisites:
            a,b = pre[0], pre[1]
            ind[b] += 1
            course[a].append(b)
        deq = deque()
        for i in range (0, numCourses):
            if ind[i] == 0:
                deq.append(i)
        
        while deq:
            x = deq.popleft()
            answer.append(x)
            for y in course[x]:
                ind[y] -= 1
                if ind[y] == 0:
                    deq.append(y)
        if len(answer) != numCourses:
            return []
        return answer[::-1]

 

 

240. Search a 2D Matrix II

 

2차원 배열에서 찾고자 하는 target이 있는지 확인하는 방법

처음 알게 된건데, any를 활용하는 방법이 있다는 것을 알게 되었다.

계산 시간도 굉장히 좋다.

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        return any(target in row for row in matrix)

 

 

 

이전 스터디의 기억을 되짚어가며 .... 선수과목이라는 문제를 풀었습니다.

옛날 LeetCode에서의 문제와 거의 유사한 것 같네요.

indegree의 차수를 항상 유의하면서 카운팅을 하면 되겠습니다.

 

import sys
from collections import deque
input = sys.stdin.readline

N, M = map(int,input().split())
node_ind = [0 for _ in range (0, N+1)]
answer = [1 for _ in range (0, N+1)]
gp = [[] for _ in range (0, N+1)]
for _ in range (0,M):
    a, b = map(int,input().split())
    gp[a].append(b)
    node_ind[b] += 1

deq = deque()
for i in range (1, N+1):
    # 해당 학기에 바로 이수할 수 있다느 뜻이므로
    if node_ind[i] == 0:
        deq.append(i)

while deq:
    x = deq.popleft()
    for y in gp[x]:
        node_ind[y] -= 1
        if node_ind[y] == 0:
            answer[y] = answer[x] + 1
            deq.append(y)
print(*answer[1:])

+ Recent posts