728x90
728x90
728x90

삼각달팽이

from math import sqrt

def n_to_total(n):
    # 4->10
    # 5->15
    # 6->21
    # n->n(n+1)/2
    return n*(n+1) // 2

def remains_to_edge_size(remains):
    # 1->1, 예외처리
    # 3->1
    # 6->2
    # 10->3
    # 15->4
    # 21->5
    # 28->6
    # 36->7
    # n(n+1)/2 -> n-1
    return round(((-1 + sqrt(1+8*remains))/ 2) - 1)

def edge_size_consumed(edge_size):
    return 3 * edge_size

def get_first(start_val, start_row_idx, start_col_idx, edge_size):
    return list(zip([*range(start_val, start_val + edge_size)], [*range(start_row_idx, start_row_idx + edge_size)], [start_col_idx]*(edge_size)))

def get_second(start_val, start_row_idx, start_col_idx, edge_size):
    return list(zip([*range(start_val+edge_size, start_val+2*edge_size)], [start_row_idx+edge_size] * edge_size, [*range(start_col_idx, start_col_idx + edge_size)]))

def get_third(start_val, start_row_idx, start_col_idx, edge_size):
    return list(zip([*range(start_val+2*edge_size, start_val+3*edge_size)], [*range(start_row_idx+edge_size, start_row_idx, -1)], [*range(start_col_idx+edge_size, start_col_idx, -1)]))

def solution(n):
    if n == 1:
        return [1]
    answer = [[0]*i for i in range(1, 1 + n)]
    funcs = [get_first, get_second, get_third]

    start_val = 1
    start_row_idx = 0  # increment : 2
    start_col_idx = 0  # increment : 1
    remains = n_to_total(n)
    edge_size = remains_to_edge_size(remains)    

    while (remains):
        for func in funcs:
            val_row_cols = func(start_val, start_row_idx, start_col_idx, edge_size)
            for val, row, col in val_row_cols:
                answer[row][col] = val
        consumed = edge_size_consumed(edge_size)
        start_val += consumed
        start_row_idx += 2
        start_col_idx += 1
        remains -= consumed
        edge_size = remains_to_edge_size(remains)
        if remains == 1:
            answer[start_row_idx][start_col_idx] = start_val
            remains -= 1

    answer = [x for sublist in answer for x in sublist]
    return answer
  • 포인트
    • 각 삼각형을 외곽부터 layer-1, layer-2, …
    • 각 layer마다 세 개의 변으로 나눠 처리(왼쪽, 밑, 오른쪽을 first, second, third)
    • 이런 군수열방식이 아닌, 방향 개념 도입해서 풀면 더 간단할 듯
728x90
728x90
def get_rotation_candidates(mat, query):
    x1, y1, x2, y2 = query
    # (x, y, val)
    first = [(x1-1, y1 -1 + i, mat[x1-1][y1-1+i]) for i in range(y2-y1)]
    second = [(x1-1+i, y2-1, mat[x1-1+i][y2-1]) for i in range(x2-x1)]
    third = [(x2-1, y2-1-i, mat[x2-1][y2-1-i]) for i in range(y2-y1)]
    fourth = [(x2-1-i,y1-1, mat[x2-1-i][y1-1]) for i in range(x2-x1)]    
    return first, second, third, fourth

def get_min(first, second, third, fourth):
    return min(
        min(first, key=lambda x: x[2])[2],
        min(second, key=lambda x: x[2])[2], 
        min(third, key=lambda x: x[2])[2], 
        min(fourth, key=lambda x: x[2])[2], 
    )

def rotate(mat, first, second, third, fourth):
    mat[first[0][0]][first[0][1]] = fourth[-1][-1]
    mat[second[0][0]][second[0][1]] = first[-1][-1]
    mat[third[0][0]][third[0][1]] = second[-1][-1]
    mat[fourth[0][0]][fourth[0][1]] = third[-1][-1]

    if len(first) >= 2:
        for i in range(1, len(first)):
            new_val = first[i-1][-1]
            mat[first[i][0]][first[i][1]] = new_val
    if len(second) >= 2:
        for i in range(1, len(second)):
            new_val = second[i-1][-1]
            mat[second[i][0]][second[i][1]] = new_val
    if len(third) >= 2:
        for i in range(1, len(third)):
            new_val = third[i-1][-1]
            mat[third[i][0]][third[i][1]] = new_val
    if len(fourth) >= 2:
        for i in range(1, len(fourth)):
            new_val = fourth[i-1][-1]
            mat[fourth[i][0]][fourth[i][1]] = new_val    
    return mat

def solution(rows, columns, queries):
    init_mat = [[i for i in range(1 + (j-1)*columns, 1 + j * columns)] for j in range(1, 1 + rows)]
    mins = []
    for query in queries:
        first, second, third, fourth = get_rotation_candidates(init_mat, query)
        mins.append(get_min(first, second, third, fourth))
        init_mat = rotate(init_mat, first, second, third, fourth)
    return mins
  • 포인트
    • min(listOfTuples, key=lambda x: x[2])[2] 을 통해 third element 최솟값 얻기
    • 테두리를 4분할해서 처리, 각 분할마다 첫점과 그 외를 나눠 해결
728x90
728x90
def calc_meet_x_y(line1, line2):
    A, B, E = line1
    C, D, F = line2
    AD_BC = A*D - B*C
    if AD_BC == 0:
        return None
    BF_ED = B*F - E*D
    EC_AF = E*C - A*F
    return (BF_ED)/(AD_BC), (EC_AF)/(AD_BC)

def isinteger(x):
    return int(x) == x

def transform_to_new_2d(point, max_min):
    x, y = point
    return x - max_min['min_x'], y - max_min['min_y']

def solution(line):
    max_min = {}
    met_points = []
    for outer_idx in range(len(line)):
        line1 = line[outer_idx]
        for inner_idx in range(outer_idx+1, len(line), 1):
            line2 = line[inner_idx]
            calc = calc_meet_x_y(line1, line2)
            if calc:
                x, y = calc
                if isinteger(x) and isinteger(y):
                    x, y = int(x), int(y)
                    if max_min.get('max_x', x) <= x:
                        max_min['max_x'] = x
                    if max_min.get('max_y', y) <= y:
                        max_min['max_y'] = y
                    if max_min.get('min_x', x) >= x:
                        max_min['min_x'] = x
                    if max_min.get('min_y', y) >= y:
                        max_min['min_y'] = y
                    met_points.append((x,y))


    outer_array_len = max_min['max_y'] - max_min['min_y'] + 1
    inner_array_len = max_min['max_x'] - max_min['min_x'] + 1

    answer = [["."]*inner_array_len for _ in range(outer_array_len)]
    for point in met_points:
        x, y = transform_to_new_2d(point, max_min)
        answer[y][x] = '*'
    answer = [''.join(row) for row in answer]
    return answer[::-1]
  • 포인트
    • numeric x가 integer인지 확인은 int(x) == x
    • 계속 max_x, max_y, min_x, min_y를 추적하기
    • string은 immutable이니까 2d-array로 answer template 만들기(not 1d of str)
728x90

+ Recent posts