알고리즘 스터디 44일차

창고지기·2025년 8월 6일
0

알고리즘스터디

목록 보기
49/60
post-thumbnail

1. 가장 큰 정사각형

1) 문제

1와 0로 채워진 표(board)가 있습니다. 표 1칸은 1 x 1 의 정사각형으로 이루어져 있습니다. 표에서 1로 이루어진 가장 큰 정사각형을 찾아 넓이를 return 하는 solution 함수를 완성해 주세요. (단, 정사각형이란 축에 평행한 정사각형을 말합니다.)

예를 들어

1 2 3 4
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 0
가 있다면 가장 큰 정사각형은

1 2 3 4
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 0
가 되며 넓이는 9가 되므로 9를 반환해 주면 됩니다.

제한사항
표(board)는 2차원 배열로 주어집니다.
표(board)의 행(row)의 크기 : 1,000 이하의 자연수
표(board)의 열(column)의 크기 : 1,000 이하의 자연수
표(board)의 값은 1또는 0으로만 이루어져 있습니다.

입출력 예
board answer
[[0,1,1,1],[1,1,1,1],[1,1,1,1],[0,0,1,0]] 9
[[0,0,1,1],[1,1,1,1]] 4

2) 문제 분석 및 풀이

1) 설계, 분석

2) 풀이

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int solution(vector<vector<int>> board)
{
    int answer = 0;
    int row = board.size();
    int col = board[0].size();
    vector<vector<int>> dp(row, vector<int>(col));
    answer = dp[0][0] = board[0][0];

    //dp[i][j] => i,j를 우하단 꼭지점으로 하는 정사각형의 한변의 길이
    for (int i=1; i<col; i++)
        dp[0][i] = board[0][i];

    for (int i=1; i<row; i++)
        dp[i][0] = board[i][0];

    for (int i=1; i<row; i++)
    {
        for (int j=1; j<col; j++)
        {
            if (board[i][j] == 1)
            {
                dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]})+1;
            }
            else if (board[i][j] == 0)
                dp[i][j] = 0;

            answer = max(answer, dp[i][j]);
        }
    }

    return answer * answer;
}

2. 단어 퍼즐

1) 문제

단어 퍼즐은 주어진 단어 조각들을 이용해서 주어진 문장을 완성하는 퍼즐입니다. 이때, 주어진 각 단어 조각들은 각각 무한개씩 있다고 가정합니다. 예를 들어 주어진 단어 조각이 [“ba”, “na”, “n”, “a”]인 경우 "ba", "na", "n", "a" 단어 조각이 각각 무한개씩 있습니다. 이때, 만들어야 하는 문장이 “banana”라면 “ba”, “na”, “n”, “a”의 4개를 사용하여 문장을 완성할 수 있지만, “ba”, “na”, “na”의 3개만을 사용해도 “banana”를 완성할 수 있습니다. 사용 가능한 단어 조각들을 담고 있는 배열 strs와 완성해야 하는 문자열 t가 매개변수로 주어질 때, 주어진 문장을 완성하기 위해 사용해야 하는 단어조각 개수의 최솟값을 return 하도록 solution 함수를 완성해 주세요. 만약 주어진 문장을 완성하는 것이 불가능하면 -1을 return 하세요.

제한사항
strs는 사용 가능한 단어 조각들이 들어있는 배열로, 길이는 1 이상 100 이하입니다.
strs의 각 원소는 사용 가능한 단어조각들이 중복 없이 들어있습니다.
사용 가능한 단어 조각들은 문자열 형태이며, 모든 단어 조각의 길이는 1 이상 5 이하입니다.
t는 완성해야 하는 문자열이며 길이는 1 이상 20,000 이하입니다.
모든 문자열은 알파벳 소문자로만 이루어져 있습니다.

입출력 예
strs t result
["ba","na","n","a"] "banana" 3
["app","ap","p","l","e","ple","pp"] "apple" 2
["ba","an","nan","ban","n"] "banana" -1

2) 문제 분석 및 풀이

1) 설계, 분석

2) 풀이

#include <string>
#include <vector>
#include <unordered_set>
#include <algorithm>
using namespace std;

int solution(vector<string> strs, string t)
{
    int answer = 0;
    unordered_set<string> piecesHahsSet(strs.begin(), strs.end());
    //dp[n] <- t[0] + ... + t[N] 까지의 문자열을 만드는데 사용되는 최소 조각 수
    vector<int> dp(t.size());

    // 맨 처음 문자열을 만드는데 필요한 최소조각 작성
    dp[0] = piecesHahsSet.find(t.substr(0,1)) != piecesHahsSet.end() ? 1 : 0;
   
    string currentStr = t.substr(0,1);
    for (int i=1; i<t.size(); i++)
    {
        // 현재까지의 문자열 누적
        currentStr += t[i];
        int cnt = 5;
        int minimum = t.size() + 1;    

        // i에서 최대 5글자 뒤로 탐색하며 조각이 있는지 확인
        // ex) capple -> (cappl, e) (capp, le), (cap, ple), (ca, pple), (c, apple)
        // 위 경우에서 분리된 오른쪽 문자가 조각에 포함되면
        // 좌측 마지막까지의 문자열을 만드는 최소 조각수 + 1
        // 이 중에서 최솟값으로 갱신
        for (int j=i; cnt>=0 && j>=0; j--, cnt--)
        {
            // 문자열 분할 (최대5칸)
            string right = currentStr.substr(j);
            // 분할된 문자가 조각들에 포함되면
            if (piecesHahsSet.find(right) != piecesHahsSet.end())
            {
                // 처음부터 조각으로 시작하는 경우
                if (currentStr == right && i <= 4) minimum = min(minimum, 1);
                else
                {
                    // 오른 쪽 문자열이 조각에 있으면서, 좌측 마지막까지의 문자열을 만는 조합이 있으면
                    if (dp[j-1] != 0)
                        minimum = min(dp[j-1] + 1, minimum);
                }
            }
        }
        //최솟값으로 갱신
        dp[i] = minimum == t.size() + 1 ? 0 : minimum;
    }
    return dp[t.size()-1] == 0 ? -1 : dp[t.size()-1];
}

profile
일단 창고에 넣어놓으면 언젠가는 쓰겠지

0개의 댓글