hyelie
hyelie
Hyeil Jeong
       
글쓰기    관리    수식입력
  • 전체보기 (495)
    • PS (283)
      • Algorithm (28)
      • PS Log (244)
      • Contest (6)
      • Tips (5)
    • Development (52)
      • Java (14)
      • Spring (23)
      • SQL (2)
      • Node.js (2)
      • Socket.io (3)
      • Study (4)
      • Utils (4)
    • DevOps (36)
      • Git (5)
      • Docker (4)
      • Kubernetes (2)
      • GCP (3)
      • Environment Set Up (8)
      • Tutorial (12)
      • Figma (2)
    • CS (74)
      • OOP (7)
      • OS (24)
      • DB (2)
      • Network (24)
      • Architecture (0)
      • Security (2)
      • Software Design (0)
      • Parallel Computing (15)
    • Project (15)
      • Project N2T (5)
      • Project ASG (0)
      • Project Meerkat (1)
      • Model Checking (7)
      • Ideas (2)
    • 내가 하고싶은 것! (34)
      • Plan (16)
      • Software Maestro (10)
      • 취준 (8)
hELLO · Designed By 정상우.
hyelie

hyelie

23.08.04. 풀었던 문제들 복기
PS/PS Log

23.08.04. 풀었던 문제들 복기

Leetcode 139. Word Break, 1시간

첫 접근

 처음에는 일단 brute-force로 접근했다. for문으로는 돌릴 수 없어서, dfs를 사용한 backtracking으로 접근했다. 코드는 뭐.. 간단하다. DFS(i)는 i부터 s.length()까지 만들 수 있는지 여부이다. 내부적인 구현은, i부터 모든 wordDict를 순회하면서 끝까지 도달할 수 있으면 true, 아니면 false인 식으로

class Solution {
public:
    bool DFS(int i, string& s, vector<string>& wordDict){
        if(i == s.length()) return true;

        for(string word : wordDict){
            int wordlen = word.length();
            if(s.substr(i, wordlen) == word){
                bool result = DFS(i + wordlen, s, wordDict);
                if(result) return result;
            }
        }
        return false;
    }
    bool wordBreak(string s, vector<string>& wordDict) {
        return DFS(0, s, wordDict);
    }
};

 TLE 난다.

 

두 번째 접근

 TLE가 나는 이유 중 하나는 탐색했던 것을 또 탐색하기 때문이다. 예를 들어 DFS(10)을 이미 탐색했는데 또 탐색하는 일이 발생하기 때문에, DP를 사용하면 해결된다.

 이미 탐색한 내용이라면 그 값을 돌려주게 설정하고, 새로운 탐색이 이뤄지면 그 값을 저장하게 한다. 생각보다 별 것 없는 DP.

// Runtime 2 ms Beats 91.83%
// Memory 7.7 MB Beats 85.40%

class Solution {
public:
    vector<int> dp;
    bool DFS(int i, string& s, vector<string>& wordDict){
        if(i == s.length()) return true;
        if(dp[i] != -1) return dp[i];

        for(string word : wordDict){
            int wordlen = word.length();
            if(s.substr(i, wordlen) == word){
                bool result = DFS(i + wordlen, s, wordDict);
                dp[i] = result;
                if(result) return result;
            }
        }
        dp[i] = false;
        return false;
    }
    bool wordBreak(string s, vector<string>& wordDict) {
        dp.resize(s.length());
        fill(dp.begin(), dp.end(), -1);
        return DFS(0, s, wordDict);
    }
};

/*
dp[i] : i부터 끝까지 봤을 때 만들 수 있는지
*/

 

 

 

후기

 생각보다 별 것 없는 DP이지만, + 첫 접근도 잘 했지만 DP는 너무 어렵다.

 

 

 

BOJ 1543. 문서 검색, 6분

 string의 find 함수와 getline만 알고 있다면 벌 이상없이 쉽게 풀리는 문제. find() 함수를 잘 써 보자.

void solve(){
	string doc, s;
    getline(cin, doc);
    getline(cin, s);

    int answer = 0, idx = 0;
    while(1){
        int nth_idx = doc.find(s, idx);
        if(nth_idx == string::npos) break;

        answer++;
        idx = nth_idx+s.length();
    }
    cout<<answer;
}

 

 

 

BOJ 28419. 더하기, 10분

 직관으로 풀 수 있는 문제. 단, 범위를 유의해야 했다.

 짝수 합, 홀수 합으로 나누고,

  • even sum에 2를 더하고 odd sum에 1 더하거나
  • even sum에 1 더하고 odd sum에 2 더하거나

 위 2개의 operation을 수행할 수 있다. 따라서 even sum - odd sum의 절댓값을 리턴하면 된다.

 

 단, N == 3인 경우 위의 operation만 수행할 수 있으므로 evensum이 더 크다면 -1.

ll solve(){
	int n; cin>>n;
    ll oddsum = 0, evensum = 0;
    int input;
    for(int i = 0; i<n; i++){
        cin>>input;
        if(i % 2 == 0) evensum += input;
        else oddsum += input;
    }

    if(oddsum == evensum) return 0;
    if(n == 3 && evensum > oddsum) return -1;
    return abs(evensum - oddsum);

    // 연산은 총 2가지.
    // evensum에 2 더하고 oddsum에 1 더하거나
    // evensum에 1 더하고 oddsum에 2 더하거나.
    // N == 3인 경우는 1번밖에 못함. -> evensum이 더 큰 경우 불가능.
}

 

 

 

BOJ 21773. 가희와 프로세스, 30분

 문제가 던져주는 대로 구현하면 되는 문제. priority를 쓰니까, 당연히 priority queue를 써야 한다.

 유의해야 할 점은, 진짜 주는 대로 구현하면, 각 연산이 O(nlogn)만큼의 시간을 쓰기 때문에 전체 시간이 O(Tnlogn)이 되어서 TLE가 난다. 떄문에 [현 작업을 제외한 나머지 priority를 증가시킨다]의 의미를 잘 생각해 봐야 한다.

 현 작업의 priority를 1 감소시키는 것 == 다른 모든 작업의 priority를 1 증가시키는 것과 동일하다.

struct process{
    int id, time, priority;
};

struct comp{
    bool operator()(const process &a, const process &b){
        if(a.priority == b.priority) return a.id > b.id;
        return a.priority < b.priority;
    }
};

void solve(){
    int T, n; cin>>T>>n;
    priority_queue<process, vector<process>, comp> pq;
    for(int i = 0; i<n; i++){
        process p;
        cin>>p.id>>p.time>>p.priority;
        pq.push(p);
    }

    while(T--){
        process p = pq.top(); pq.pop();
        cout<<p.id<<'\n';
        p.time--;
        if(p.time == 0) continue;
        p.priority--;
        pq.push(p);
    }
}

 

 

 

BOJ 6593. 상범 빌딩, 15분

 정석 BFS 문제. BFS하듯 dr/dc/dl 쓰면 되고, q에 넣을 때 visited = true만 해 주면 된다. 그리고 좌표 기반이니까 다음 좌표로 넘어갈 때 seg fault 안 나게 검사해 주고, unvisited 검사하면 된다.

struct coord{
    int l, r, c;
};

int dr[6] = {1, 0, -1, 0, 0, 0};
int dc[6] = {0, 1, 0, -1, 0, 0};
int dl[6] = {0, 0, 0, 0, 1, -1};

string solve(int L, int R, int C){
    coord S, E;
    vector<vector<vector<char>>> dimension(L, vector<vector<char>>(R, vector<char>(C)));
    vector<vector<vector<bool>>> visited(L, vector<vector<bool>>(R, vector<bool>(C, false)));
    for(int l = 0; l<L; l++){
        for(int r = 0; r<R; r++){
            for(int c = 0; c<C; c++){
                cin>>dimension[l][r][c];
                if(dimension[l][r][c] == 'S'){
                    S.l = l; S.r = r; S.c = c;
                }
                else if(dimension[l][r][c] == 'E'){
                    E.l = l; E.r = r; E.c = c;
                }
            }
        }
    }

    queue<pair<coord, int>> q;
    q.push({S, 0});
    visited[S.l][S.r][S.c] = true;
    while(!q.empty()){
        coord f = q.front().first; int fmin = q.front().second; q.pop();
        if(f.l == E.l && f.r == E.r && f.c == E.c){
            return "Escaped in " + to_string(fmin) + " minute(s).";
        }
        
        for(int i = 0; i<6; i++){
            int nl = f.l + dl[i];
            int nr = f.r + dr[i];
            int nc = f.c + dc[i];
            if(0 <= nl && nl < L && 0 <= nr && nr < R && 0 <= nc && nc < C && dimension[nl][nr][nc] != '#' && !visited[nl][nr][nc]){
                q.push({{nl, nr, nc}, fmin + 1});
                visited[nl][nr][nc] = true;
            }
        }
    }
    return "Trapped!";
}

//////////////////////

int main(void) {
	cin.tie(0);
	cout.tie(0);
	std::ios_base::sync_with_stdio(0);

    int L, R, C;
    while(1){
        cin>>L>>R>>C;
        if(L == 0 && R == 0 && C == 0) break;
        cout<<solve(L, R, C)<<'\n';
    }

	return 0;
}

 

 

 

BOJ 11576. base conversion, 6분

 A진법을 10진법으로 바꿨다가 B진법으로 바꾸면 된다. 별 것 없는 문제.

void solve(){
	int A, B; cin>>A>>B;
    int m; cin>>m;
    vector<int> digits(m);
    for(int i = m-1; i>=0; i--) cin>>digits[i];

    int ten = 0, mul = 1;
    for(int digit : digits){
        ten += digit * mul;
        mul *= A;
    }

    vector<int> result;
    while(ten){
        result.push_back(ten % B);
        ten /= B;
    }
    for(int i = result.size()-1; i>=0; i--) cout<<result[i]<<' ';

}

 

 

 

BOJ 4396. 지뢰 찾기, 25분

 코드는 좀 길게 작성되었는데. 오타 몇 개 때문에 시간을 좀 보냈다.

int dr[8] = {1, 1, 1, 0, 0, -1, -1, -1};
int dc[8] = {1, 0, -1, 1, -1, 1, 0, -1};

void solve(){
	int n; cin>>n;
    vector<vector<bool>> isMine(n, vector<bool>(n, false)); // mine(*)이면 true, else false
    vector<vector<int>> numMine(n, vector<int>(n, 0));

    for(int i = 0; i<n; i++){
        for(int j = 0; j<n; j++){
            char input; cin>>input;
            if(input == '*'){
                isMine[i][j] = true;
                for(int d = 0; d<8; d++){
                    int nr = i + dr[d];
                    int nc = j + dc[d];
                    if(0 <= nr && nr < n && 0 <= nc && nc < n){
                        numMine[nr][nc]++;
                    }
                }
            }
        }
    }

    bool isExplode = false;
    vector<vector<bool>> isInput(n, vector<bool>(n, false)); // isInput(x)면 true, else false
    for(int i = 0; i<n; i++){
        for(int j = 0; j<n; j++){
            char input; cin>>input;
            if(input == 'x'){
                isInput[i][j] = true;
                if(isMine[i][j]) isExplode = true;
            }
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if(isExplode && isMine[i][j]) cout<<'*';
            else if(isInput[i][j]) cout<<numMine[i][j];
            else cout<<'.';
        }
        cout << '\n';
    }
}

 

 

 

후기

 solved.ac에서 랜덤 돌릴 때 *s..g !@$me로 [내가 풀지 않았던 실버~골드 문제]로 추출해서 푼다.

solved.ac 실버~골드 문제 비율

 문제 비율은 골드가 훨씬 더 높은 것 같은데.. 영어 문제를 제해서 그런가? 실버 문제가 굉장히 많이 나오는 느낌이 든다.

 

 가능하면, 실버 문제들은 정확하고, 빠르게 + 원큐에 풀 수 있도록 해 보자. 솔직히 문제를 잘못 풀어서 걸리는 overhead보다 문제를 정확하게 읽는 조금의 overhead가 훨씬 적으니까.

 

저작자표시 (새창열림)

'PS > PS Log' 카테고리의 다른 글

23.08.07. 풀었던 문제들 복기  (0) 2023.08.09
23.08.05. 풀었던 문제들 복기  (0) 2023.08.05
23.08.02. 풀었던 문제들 복기  (0) 2023.08.02
23.08.01. 풀었던 문제들 복기  (0) 2023.08.01
23.07.31. 풀었던 문제들 복기  (0) 2023.08.01
    hyelie
    hyelie

    티스토리툴바