Red Glitter Pointer

 

 

안녕하세요~~

오늘은 홈택스에서 "소득확인증명서"와 "사실증명(신고사실없음)" 서류 발급 방법에 대해 알려드릴게요 ㅎㅎ

 

기존 가입했던 주택청약저축을 청년우대형으로 전환 가능한지 확인하기 위해 은행 모바일 어플로 신청하고 있었는데, "소득확인증명서"서류를 발급받아야 하더라구요!

 

그래서 해당 서류를 발급받는 방법에 대해 알려드릴거에요!!!

 

1. 홈택스 접속

 

우선, 홈택스 웹사이트에 접속해주세요!

https://www.hometax.go.kr/websquare/websquare.html?w2xPath=/ui/pp/index_pp.xml

 

국세청 홈택스

 

www.hometax.go.kr

 

 

2. 로그인

저는 카카오톡 인증으로 로그인 했습니다!

 

 

 

3. 해당 메뉴 클릭

 

23년 기준으로 신고 내역이 있으셨던 분들은 "소득확인증명서(청년우대형주택청약종합저축 가입 및 과세특례 신청용)"을 누르시면 되고, 없으셨던 분들은 "신고사실없음" 을 눌러서 신청하시면 돼요!

 

저는 작년 기준으로는 소득이 없었기 때문에, 처음에 소득확인 증명서를 신청했을 때 "처리(발급)불가"라고 뜨더라구요 ㅠㅠ 

 

발급 불가 사유: 신고내역이 없습니다.

 

 

 

그래도 다행히, 아래와 같이 불가 사유 및 담당 세무서와 전화번호까지 함께 안내메시지가 팝업되어서 좋았어요!

 

 

 

위 팝업된 안내메시지에 떠있는 세무서로 전화해보니, 23년도 기준 신고 내역이 없을 경우 사실증명(신고사실없음) 서류를 신청하면 된다고 하시더라구요! 3시간 이내로 처리 된다고 하네요 👏👏

저는 30분만에 처리 완료됐습니다!

 

 

 

 

4. 처리 내역 확인

 

신청이 잘 되었는지까지 확인!! 사실증명이 처리가 완료되면, 은행에 바로 제출해야겠어요 ㅎㅎ

국세청에 전화했을 땐 은행에 사실증명(신고사실없음) 위 서류로 제출하면 된다고 하셨는데,

은행에서는 위 서류로 해줄지는 모르겠네요 ㅠ .. 일단 제출 해봐야겠습니다..ㅎㅎ

 

 

 

소득확인증명서와 사실증명 발급 방법에 대해 알려드렸습니다!!

도움이 되셨길 바랍니다 ㅎㅎ

 

 

 

   ♡ ♡ ᕬ ᕬ ♡ ♡
  + ♡ ( ⌯′-′⌯) ♡ +
┏━♡━ U U━♡━┓
♡   공감과 댓글  ♡

♡  부탁드립니당   ♡
┗━♡━━━━♡━┛

 

 

flutter_oss_licenses | Dart package

A tool to generate detail and better OSS license list using pubspec.yaml/lock files.

pub.dev

 

 

1. flutter_oss_licenses 설치

 

👇 pubspec.yaml 에 추가

dev_dependencies:
  flutter_oss_licenses: ^3.0.2

 

공식홈페이지에 나와있는대로 3.0.2버전을 설치하려고 했으나 아래와 같은 에러 발생, 터미널에 나와있는대로 downgrade했다. 2.0.1로 진행함! 

 

 

👇 터미널창에 입력

flutter pub get
flutter pub run flutter_oss_licenses:generate.dart

 

🪸 두번째 명령어까지 입력하면 프로젝트 최상위에 oss_licenses.dart 파일 자동생성된다.

🪸 해당 파일 안에는 현재 프로젝트에 사용하고 있는 모든 패키지의 licenses 정보가 json 형태로 저장됨!

 

⚠️ 자동으로 생성된 oss_licenses.dart에는 모든 패키지가 다 저장되기 때문에, 명시할 패키지만 남겨두고 삭제하면 된다 

 

 

생성된 oss_licenses.dart 파일의 구조는 아래와 같다.

 

 

 

2. 페이지 생성

oss_licenses.dart에 있는 package들을 보여줄 page를 생성한다

 

👇 oss_licenses_page.dart

import 'package:flutter/material.dart';
import 'package:test/oss_licenses.dart';
import 'package:test/misc_oss_license_single.dart';

class OssLicensesPage extends StatelessWidget {
  const OssLicensesPage({super.key});

  static Future<List<String>> loadLicenses() async {
    final ossKeys = List<String>.from(ossLicenses);
    return ossKeys..sort();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('오픈소스 라이선스')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            for (var i = 0; i < ossLicenses.length; i++)
              ListTile(
                title: Text(ossLicenses[i].name),
                subtitle: Text(ossLicenses[i].description),
                trailing: Icon(Icons.chevron_right),
                onTap: () {
                  Navigator.of(context).push(
                    MaterialPageRoute(
                      builder: (context) => MiscOssLicenseSingle(
                        name: ossLicenses[i].name,
                        version: ossLicenses[i].version,
                        description: ossLicenses[i].description,
                        licenseText: ossLicenses[i].license ?? '',
                        homepage: ossLicenses[i].homepage ?? '',
                      ),
                    ),
                  );
                },
              )
          ],
        ),
      ),
    );
  }
}

 

 

👇 misc_oss_license_single.dart

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class MiscOssLicenseSingle extends StatelessWidget {
  final String name;
  final String version;
  final String description;
  final String licenseText;
  final String homepage;

  MiscOssLicenseSingle({
    super.key,
    required this.name,
    required this.version,
    required this.description,
    required this.licenseText,
    required this.homepage,
  });

  String _bodyText() {
    return licenseText.split('\n').map((line) {
      if (line.startsWith('//')) line = line.substring(2);
      line = line.trim();
      return line;
    }).join('\n');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: [
            ListTile(
              title: Text(name),
              subtitle: Text('version : $version'),
            ),
            Padding(
                padding:
                    const EdgeInsets.all(12),
                child: Text(description)),
            const Divider(),
            Padding(
              padding:
                  const EdgeInsets.all(12),
              child: Text(_bodyText()),
            ),
            const Divider(),
            ListTile(
              title: Text('Homepage'),
              subtitle: Text(homepage),
              onTap: () async {
                final Uri homepageUri = Uri.parse(homepage);
                if (await canLaunchUrl(homepageUri)) {
                  await launchUrl(homepageUri);
                } else {
                  throw '해당 페이지로 이동할 수 없습니다. $homepage';
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

 

 

3. 결과물

목록
누르면 위 상세 페이지로 이동!

 

 

현재 진행중인 프로젝트에서는 text나 color, header 등 style을 별도로 지정해서 사용했기 때문에 그대로 올릴 수 없어서 위에 올린 코드에는 복붙만해도 정상작동 되게끔 수정해서 올렸다. 그래서 업로드한 스크린샷과 디자인은 조금 다를 수 있음! 

 

 

6236번: 용돈 관리

현우는 용돈을 효율적으로 활용하기 위해 계획을 짜기로 하였다. 현우는 앞으로 N일 동안 자신이 사용할 금액을 계산하였고, 돈을 펑펑 쓰지 않기 위해 정확히 M번만 통장에서 돈을 빼서 쓰기로

www.acmicpc.net

 

 

 

👇 내가 작성한 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        int[] account = new int[N];

        for(int i = 0; i < N; i++) {
            account[i] = Integer.parseInt(br.readLine());
        }

        int left = Arrays.stream(account).max().getAsInt(); // 모든 지출 중 최대값
        int right = Arrays.stream(account).sum(); // 모든 지출의 합
        int K = 0;

        while(left <= right) {
            int mid = (left + right) / 2; // 날짜 별 지출을 mid 금액으로 커버할 수 있는지 확인
            int sum = 0;
            int count = 1; // 인출 횟수

            for(int money : account) {
                // 현재까지의 sum에 다음 일자의 금액을 더했을 때, mid보다 크다면 재인출
                // 현재 인출한 금액으로는 다음 일자의 금액을 충당할 수 없다는 의미
                if(sum + money > mid) {
                    count++; // 재인출
                    sum = 0;
                }
                sum += money; // 현재일자 금액 더하기
            }

            // 인출 횟수가 M이하인지 검색하고 가능한 최소 금액 찾기
            // 인출 금액을 줄여볼 수 있는 여지가 있음
            if(count <= M) {
                right = mid - 1;
                K = mid;
            } else left = mid + 1;
            // count가 M보다 크다면, 인출 횟수가 너무 많다는 얘기. == mid 금액 증가
        }
        System.out.println(K);
    }
}

 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

 

👇 내가 작성한 코드

import java.util.*;

class Solution {
    public String solution(int[] numbers) {
        String[] arr = new String[numbers.length];
        
        for(int i = 0; i < numbers.length; i++) {
            arr[i] = String.valueOf(numbers[i]);
        }
        
        // 두 수를 합친 값을 기준으로 내림차순
        // o1 : 30, o2 : 5 일 경우, 305와 530 중 더 큰 값 비교
        Arrays.sort(arr, (o1, o2) -> (o2 + o1).compareTo(o1 + o2));
        
        // 정렬된 배열의 맨 처음이 0이라면 0으로만 되어있음. 0 반환
        return arr[0].equals("0") ? "0" : String.join("", arr);
    }
}

 

 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

👇 내가 제출한 코드

import java.util.*;

class Solution {
    public long solution(int n, int[] times) {
        long answer = 0;
        Arrays.sort(times); // 이분 탐색을 위해 정렬

        long left = 0;
        long right = (long) n * times[times.length - 1]; // 최악의 경우 고려
        
        while(left <= right) {
            long mid = (left + right) / 2;
            
            long sum = 0; // 심사한 인원
            for(int time : times) {
                sum += mid / time;
            }
            
            // n명 심사해야하는데 못했다면, 시간이 더 필요하기 때문에 left 옮겨줌
            if(sum < n) left = mid + 1;
            // n명 이상 했다면 시간을 줄여서 최적의 시간을 확인해보기
            else {
                right = mid - 1;
                answer = mid;
            }
        }
        return answer;
    }
}

 

 

 

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net

 

 

👇 내가 제출한 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N, M;
    static int[] dr = {-1, 0, 1, 0};
    static int[] dc = {0, -1, 0, 1};
    static int[][] ocean;
    static boolean[][] visited;
    static List<int[]> icebergs = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        ocean = new int[N][M];
        visited = new boolean[N][M];

        for(int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j = 0; j < M; j++) {
                ocean[i][j] = Integer.parseInt(st.nextToken());
                if(ocean[i][j] > 0) {
                    icebergs.add(new int[] {i, j}); // 빙산 좌표 저장
                }
            }
        }

        int time = 0;
        while(!icebergs.isEmpty()){
            time++; // 빙산 분리되는 시간
            melting(); // 빙산 녹이기

            if(searchSplit()) {
                System.out.println(time);
                return;
            }
        }
        System.out.println(0);
    }
    public static void melting() {
        int[][] tempMap = new int[N][M];
        List<int[]> nextIcebergs = new ArrayList<>();

        // 빙산 좌표 돌면서 얼마나 녹일지 확인하기
        for(int[] iceberg : icebergs) {
            int x = iceberg[0];
            int y = iceberg[1];

            int melt = 0;
            for(int d = 0; d < 4; d++) {
                int nx = dr[d] + x;
                int ny = dc[d] + y;

                if(nx >= 0 && ny >= 0 && nx < N && ny < M && ocean[nx][ny] == 0) melt++;
            }
            // 녹인 후 빙산의 높이 임시배열에 저장해두기
            tempMap[x][y] = Math.max(0, ocean[x][y] - melt);
            // 다 녹지 않았다면 좌표 저장
            if(tempMap[x][y] > 0) nextIcebergs.add(new int[] {x, y});
        }

        icebergs = nextIcebergs; // 빙산 좌표 갱신
        // 임시배열 반영하기
        for(int i = 0; i < N; i++) {
            System.arraycopy(tempMap[i], 0, ocean[i], 0, M);
        }
    }

    public static boolean searchSplit() {
        int count = 0;
        for(boolean[] row : visited) Arrays.fill(row, false); // 방문 판별 배열 초기화

        // 빙산 좌표만 dfs 돌면서 분리된 덩어리 개수 확인하기
        for(int[] iceberg : icebergs) {
            int x = iceberg[0];
            int y = iceberg[1];

            if(!visited[x][y]) {
                dfs(x, y);
                count++; // 분리된 덩어리 개수
                if(count > 1) return true;
            }
        }
        return false;
    }

    public static void dfs(int x, int y) {
        visited[x][y] = true;
        for(int d = 0; d < 4; d++) {
            int nx = dr[d] + x;
            int ny = dc[d] + y;

            if(nx >= 0 && ny >= 0 && nx < N && ny < M && !visited[nx][ny] && ocean[nx][ny] > 0) {
                dfs(nx, ny);
            }
        }
    }
}

 

 

느낀 점 및 정리 ✍️

1. 처음에 작성했던 코드는 분리된 빙산의 개수를 찾을 때 배열의 처음부터 끝까지 돌면서 dfs로 확인했었다. 그래서인지 59%에서 자꾸 시간초과가 떴었던 것 같기도.... ㅠㅠ

2. System.arrayscopy 메소드 아직 익숙하지 않아서 찾아봐야겠다. 원래 clone()만 썼었는데 무슨 차이가 있는지도 확인해봐야겠다. 

 

 

 

 

 

5052번: 전화번호 목록

첫째 줄에 테스트 케이스의 개수 t가 주어진다. (1 ≤ t ≤ 50) 각 테스트 케이스의 첫째 줄에는 전화번호의 수 n이 주어진다. (1 ≤ n ≤ 10000) 다음 n개의 줄에는 목록에 포함되어 있는 전화번호가

www.acmicpc.net

 

 

👇 내가 작성한 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int tc = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();

        while(tc-- > 0) {
            String answer = "YES";
            int N = Integer.parseInt(br.readLine());
            String[] phone_book = new String[N];
            for(int i = 0; i < N; i++) {
                phone_book[i] = br.readLine();
            }

            Arrays.sort(phone_book); // 접두어 판별을 더 빠르게 하기 위해 정렬

            for(int i = 0; i < phone_book.length - 1; i++) {
                if(phone_book[i + 1].startsWith(phone_book[i])) {
                    answer = "NO"; // 접두어라면 NO 출력 후 for문 빠져나가기
                    break;
                }
            }
            sb.append(answer).append("\n");
        }
        System.out.println(sb);
    }
}

 

 

느낀 점 및 정리 ✍️

1. String으로 정렬하면 동일한 접두사를 더 빠르게 찾을 수 있어서 정렬하여 탐색하고, 접두어를 찾게되면 for문을 빠져나오도록 작성하였다. 

 

 

 

 

15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net

 

 

👇 내가 작성한 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N, M;
    static int min = Integer.MAX_VALUE;
    static int[] selected;
    static List<int[]> house = new ArrayList<>();
    static List<int[]> chicken = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        selected = new int[M];

        for(int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j = 0; j < N; j++) {
                int value = Integer.parseInt(st.nextToken());
                if(value == 1) house.add(new int[] {i, j}); // 집 좌표 저장
                else if(value == 2) chicken.add(new int[] {i, j}); // 치킨가게 좌표 저장
            }
        }
        dfs(0, 0);
        System.out.println(min);
    }

    public static void dfs(int L, int start) {
        if(L == M) { // 유지하는 치킨집 M개 선택 완료되면 dist 메소드 실행
            dist();
            return;
        }

        // 유지할 치킨집 M개 조합하여 selected배열에 인덱스 저장
        for(int i = start; i < chicken.size(); i++) {
            selected[L] = i;
            dfs(L + 1, i + 1);
        }
    }

    public static void dist() {
        int sum = 0;
        for(int[] h : house) {
            int tempMin = Integer.MAX_VALUE;
            for(int idx : selected) { // 유지할 치킨집 M개의 인덱스가 담겨져있는 배열
                int[] hCur = chicken.get(idx);
                int distance = Math.abs(h[0] - hCur[0]) + Math.abs(h[1] - hCur[1]); // 거리 차이 구하기
                tempMin = Math.min(tempMin, distance); // 집에서 가장 가까운 치킨집 선택
            }
            sum += tempMin; // 선택한 치킨거리 누적합
        }
        min = Math.min(sum, min); // 치킨거리 최솟값 구하기
    }
}

 

 

느낀 점 및 정리 ✍️

1. dfs에서 조합 for문 돌릴 때 원하는 방식의 조합 조건이 바로바로 떠오르질 않는다 ㅠㅜ 문제 많이 풀면서 익혀야겠다

2. 거리를 구하는 문제라 어차피 좌표만 알면 돼서 2차원 배열에 별도로 저장하지 않았다

 

 

+ Recent posts

loading