public class Solution {
	
	// 쌍둥이 빌딩 숲
	// 전체 쌍둥이 빌딩의 수, 측면에서 봤을 때 보이는 빌딩의 수 [경우의 수]
	// 가장 높은 쌍둥이 빌딩부터 순서대로 배치
	// 1, 1 = 11 [1개]

	// 2, 1 = 1221, 1122 [2개] 1 * 2
	// 2, 2 = 2211 [1개] 1
	
	// 3, 1 = 133221, 123321, 122331, 122133, 133122, 113322, 112332, 112233 [8개] 2 * 4
	// 3, 2 = 233211, 223311, 221331, 221133, 331221, 331122 [6개] 1 * 4 + 2
	// 3, 3 = 332211 [1개] 1
	
	// 4, 1 = [48개] 8 * 6
	// 4, 2 = [44개] 6 * 6 + 8
	// 4, 3 = [12개] 1 * 6 + 6
	// 4, 4 = [1개] 1
	
	// 5, 1 = [384개] 48 * 8
	// 5, 2 = [400개] 44 * 8 + 48
	// 5, 3 = [140개] 12 * 8 + 44
	// 5, 4 = [20개] 1 * 8 + 12
	// 5, 5 = [1개] 1
	
	// (x, y)를 전체 쌍둥이 빌딩 x개 중, 측면에서 봤을 때 y개의 빌딩이 보이는 경우의 수라고 했을 때
	// (1, 1)은 1로 고정
	// x는 2 이상이고, y가 1일 때 (x, y)를 만드는 방법 => (x, y) = (x - 1, y) * (2 * (x - 1))
	// x는 2 이상이고, y가 1보다 크고 x보다 작을 때 (x, y)를 만드는 방법 => (x, y) = (x - 1, y) * (2 * (x - 1)) + (x - 1, y - 1)
	// x는 2 이상이고, y가 x일 때 (x, y)를 만드는 방법 => (x, y) = (x - 1, y - 1)
	
	// 11 (가장 높은 쌍둥이 빌딩 11 배치)
	// ☆☆ 1 ☆☆ 1 ☆☆ (다음으로 높은 쌍둥이 빌딩 배치할 위치 찾기)
	// 22 11 (다음으로 높은 빌딩 22를 제일 앞에 배치 시 보이는 건물 + 1, 경우의 수는 배치 전 그대로)
	// 1 22 1, 11 22 (다음으로 높은 빌딩 22를 빌딩 사이 또는 제일 뒤에 배치 시 보이는 건물 그대로, 경우의 수는 배치 전 * 2
	// 다음으로 높은 빌딩 33을 제일 앞에 배치 시 => 보이는 건물 + 1, 경우의 수는 배치 전 그대로
	// 2211(하나의 예) => 332211
	// 다음으로 높은 빌딩 33을 빌딩 사이 또는 제일 뒤에 배치 시 => 보이는 건물 그대로, 경우의 수는 배치 전 * (2 * (배치 후 쌍둥이 빌딩의 수 - 1))
	// 2211(하나의 예) => 233211, 223311, 221331, 221133
	
	// 3, 1의 경우의 수는 2, 1의 경우의 수에서만 생각 (2, 2는 이미 빌딩 2개가 보이는 상태)
	// 2, 1이 3, 1이 되기 위해서는 쌍둥이 빌딩 한 쌍을 추가로 배치하면서 보이는 건물은 그대로여야 한다. => 사이 또는 제일 뒤에 배치
	// 2, 1의 경우인 1221, 1122 경우의 수 2에 * (2 * (3 - 1)) => 3, 1 = 8개
	// 3, 2의 경우의 수는 2, 2의 경우의 수에서 사이 또는 제일 뒤에 배치, 2, 1의 경우의 수에서 제일 앞에 배치 (2가지 경우가 존재)
	// 2, 2의 경우인 2211 경우의 수 1에 * (2 * (3 - 1)) => 4
	// 2, 1의 경우인 1221, 1122 경우의 수 2 그대로
	// 3, 2 => 6개
	// 3, 3의 경우의 수는 2, 2의 경우의 수에서만 생각, 제일 앞에 배치 => 2, 2의 경우인 2211 경우의 수 1 그대로 (332211)
	
	public static int solution(int n, int count) {
		long[][] arr = new long[n + 1][n + 1];
		long preventOutOfRange = 1000000007;
		long temp = 0;
		
		arr[1][1] = 1;
		
		for (int x = 2; x <= n; x++) { // x는 2 이상
			
			for (int y = 1; y <= x; y++) {
				
				if (y == 1) { // y가 1일 때 arr[x][y]를 만드는 방법 => arr[x][y] = arr[x - 1][y] * (2 * (x - 1));
					temp = arr[x - 1][y] * (2 * (x - 1));
				} else if (y > 1 && y < x) { // y가 1보다 크고 x보다 작을 때 arr[x][y]를 만드는 방법 => arr[x][y] = arr[x - 1][y] * (2 * (x - 1)) + arr[x - 1][y - 1];
					temp = arr[x - 1][y] * (2 * (x - 1)) + arr[x - 1][y - 1];
				} else { // y가 x일 때 arr[x][y]를 만드는 방법 => arr[x][y] = arr[x - 1][y - 1];
					temp = arr[x - 1][y - 1];
				}
				
				arr[x][y] = temp % preventOutOfRange;
			}
		}
		
		return (int) arr[n][count];
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int n = 3;
		int count = 1;
		
		System.out.println(solution(n, count)); // 8
	}
}

(x, y)를 전체 쌍둥이 빌딩 x개 중, 측면에서 봤을 때 y개의 빌딩이 보이는 경우의 수라고 했을 때

(1, 1)은 1로 고정


x는 2 이상이고, y가 1일 때 (x, y)를 만드는 방법

=> (x, y) = (x - 1, y) * (2 * (x - 1))


x는 2 이상이고, y가 1보다 크고 x보다 작을 때 (x, y)를 만드는 방법

=> (x, y) = (x - 1, y) * (2 * (x - 1)) + (x - 1, y - 1)


x는 2 이상이고, y가 x일 때 (x, y)를 만드는 방법

=> (x, y) = (x - 1, y - 1)

프로그래머스 쌍둥이 빌딩 숲 문제 풀이 Java

<MySQL>

SELECT A.MEMBER_NAME
     , B.REVIEW_TEXT
     , DATE_FORMAT(B.REVIEW_DATE, '%Y-%m-%d') AS REVIEW_DATE
  FROM MEMBER_PROFILE A
     , REST_REVIEW B
 WHERE A.MEMBER_ID = B.MEMBER_ID
   AND B.MEMBER_ID IN (
                        SELECT MEMBER_ID
                          FROM REST_REVIEW
                      GROUP BY MEMBER_ID
                        HAVING COUNT(MEMBER_ID) = (
                                                    SELECT COUNT(MEMBER_ID) AS CNT
                                                      FROM REST_REVIEW
                                                  GROUP BY MEMBER_ID
                                                  ORDER BY COUNT(MEMBER_ID) DESC
                                                     LIMIT 1                      
                                                  )
                      )
 ORDER BY B.REVIEW_DATE, B.REVIEW_TEXT

<Oracle>

SELECT A.MEMBER_NAME
     , B.REVIEW_TEXT
     , TO_CHAR(B.REVIEW_DATE, 'YYYY-MM-DD') AS REVIEW_DATE
  FROM MEMBER_PROFILE A
     , REST_REVIEW B
 WHERE A.MEMBER_ID = B.MEMBER_ID
   AND B.MEMBER_ID IN (
                        SELECT MEMBER_ID
                          FROM REST_REVIEW
                      GROUP BY MEMBER_ID
                        HAVING COUNT(MEMBER_ID) = (
                                                    SELECT MAX(COUNT(MEMBER_ID)) AS CNT
                                                      FROM REST_REVIEW
                                                  GROUP BY MEMBER_ID                 
                                                  )
                      )
 ORDER BY B.REVIEW_DATE, B.REVIEW_TEXT

프로그래머스 그룹별 조건에 맞는 식당 목록 출력하기 SQL

<MySQL & Oracle>

SELECT A.CATEGORY
     , A.PRICE AS MAX_PRICE
     , A.PRODUCT_NAME
  FROM (
         SELECT CATEGORY
              , PRICE
              , PRODUCT_NAME
              , RANK() OVER (PARTITION BY CATEGORY ORDER BY PRICE DESC) AS PRICE_RANK
           FROM FOOD_PRODUCT
          WHERE CATEGORY IN ('과자', '국', '김치', '식용유')
       ) A
 WHERE A.PRICE_RANK = 1
 ORDER BY A.PRICE DESC

프로그래머스 식품분류별 가장 비싼 식품의 정보 조회하기 SQL

<MySQL>

SELECT A.REST_ID
     , A.REST_NAME
     , A.FOOD_TYPE
     , A.FAVORITES
     , A.ADDRESS
     , ROUND(AVG(IFNULL(NULLIF(B.REVIEW_SCORE, ''), 0)), 2) AS SCORE
  FROM REST_INFO A
     , REST_REVIEW B
 WHERE A.REST_ID = B.REST_ID
   AND A.ADDRESS LIKE '서울%'
 GROUP BY A.REST_ID
 ORDER BY ROUND(AVG(IFNULL(NULLIF(B.REVIEW_SCORE, ''), 0)), 2) DESC, A.FAVORITES DESC

<Oracle>

SELECT A.REST_ID
     , A.REST_NAME
     , A.FOOD_TYPE
     , A.FAVORITES
     , A.ADDRESS
     , ROUND(AVG(NVL(B.REVIEW_SCORE, 0)), 2) AS SCORE
  FROM REST_INFO A
     , REST_REVIEW B
 WHERE A.REST_ID = B.REST_ID
   AND A.ADDRESS LIKE '서울%'
 GROUP BY A.REST_ID, A.REST_NAME, A.FOOD_TYPE, A.FAVORITES, A.ADDRESS
 ORDER BY ROUND(AVG(NVL(B.REVIEW_SCORE, 0)), 2) DESC, A.FAVORITES DESC

평균 계산 함수 AVG 사용 시 주의할 점

SCORE 값이 NULL이거나 빈 값일 경우 0으로 평균 계산에 포함시키려면

<MySQL> : IFNULL(NULLIF(컬럼, ''), 컬럼 값이 NULL이거나 빈 값일 경우 보여줄 값)

=> AVG(IFNULL(NULLIF(SCORE, ''), 0))

<Oracle> : NVL(컬럼, 컬럼 값이 NULL이거나 빈 값일 경우 보여줄 값)

=> AVG(NVL(SCORE, 0))

 

프로그래머스 서울에 위치한 식당 목록 출력하기 SQL

<MySQL>

SELECT A.SALES_DATE
     , A.PRODUCT_ID
     , A.USER_ID
     , A.SALES_AMOUNT
  FROM (
         SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d') AS SALES_DATE
              , PRODUCT_ID
              , USER_ID
              , SALES_AMOUNT
           FROM ONLINE_SALE
          WHERE DATE_FORMAT(SALES_DATE, '%Y-%m') = '2022-03'
      UNION ALL 
         SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d') AS SALES_DATE
              , PRODUCT_ID
              , NULL AS USER_ID
              , SALES_AMOUNT
           FROM OFFLINE_SALE
          WHERE DATE_FORMAT(SALES_DATE, '%Y-%m') = '2022-03'
       ) A
ORDER BY A.SALES_DATE, A.PRODUCT_ID, A.USER_ID

<Oracle>

SELECT A.SALES_DATE
     , A.PRODUCT_ID
     , A.USER_ID
     , A.SALES_AMOUNT
  FROM (
         SELECT TO_CHAR(SALES_DATE, 'YYYY-MM-DD') AS SALES_DATE
              , PRODUCT_ID
              , USER_ID
              , SALES_AMOUNT
           FROM ONLINE_SALE
          WHERE TO_CHAR(SALES_DATE, 'YYYY-MM') = '2022-03'
      UNION ALL 
         SELECT TO_CHAR(SALES_DATE, 'YYYY-MM-DD') AS SALES_DATE
              , PRODUCT_ID
              , NULL AS USER_ID
              , SALES_AMOUNT
           FROM OFFLINE_SALE
          WHERE TO_CHAR(SALES_DATE, 'YYYY-MM') = '2022-03'
       ) A
ORDER BY A.SALES_DATE, A.PRODUCT_ID, A.USER_ID

 

 

 

<NULL 값을 먼저 또는 나중에 출력되도록 정렬 방법>

MySQL : ORDER BY 컬럼 IS NULL (ASC / DESC)

Oracle : ORDER BY 컬럼 (ASC / DESC) NULLS (FIRST / LAST)

 

프로그래머스 오프라인/온라인 판매 데이터 통합하기 SQL

<MySQL>

SELECT A.APNT_NO
     , B.PT_NAME
     , B.PT_NO
     , A.MCDP_CD
     , C.DR_NAME
     , A.APNT_YMD
  FROM APPOINTMENT A
     , PATIENT B
     , DOCTOR C
 WHERE A.PT_NO = B.PT_NO
   AND A.MDDR_ID = C.DR_ID
   AND DATE_FORMAT(A.APNT_YMD, '%Y-%m-%d') = '2022-04-13'
   AND A.APNT_CNCL_YN = 'N'
   AND A.MCDP_CD = 'CS'
 ORDER BY A.APNT_YMD

<Oracle>

SELECT A.APNT_NO
     , B.PT_NAME
     , B.PT_NO
     , A.MCDP_CD
     , C.DR_NAME
     , A.APNT_YMD
  FROM APPOINTMENT A
     , PATIENT B
     , DOCTOR C
 WHERE A.PT_NO = B.PT_NO
   AND A.MDDR_ID = C.DR_ID
   AND TO_CHAR(A.APNT_YMD, 'YYYY-MM-DD') = '2022-04-13'
   AND A.APNT_CNCL_YN = 'N'
   AND A.MCDP_CD = 'CS'
 ORDER BY A.APNT_YMD

프로그래머스 취소되지 않은 진료 예약 조회하기 SQL

<MySQL>

SELECT A.FLAVOR
  FROM FIRST_HALF A
 INNER JOIN (
              SELECT FLAVOR
                   , SUM(TOTAL_ORDER) AS JULY_ORDER
                FROM JULY
            GROUP BY FLAVOR
            ) B
    ON A.FLAVOR = B.FLAVOR
 ORDER BY (A.TOTAL_ORDER + B.JULY_ORDER) DESC
 LIMIT 3

<Oracle>

SELECT FLAVOR
  FROM (
         SELECT A.FLAVOR
           FROM FIRST_HALF A
     INNER JOIN (
                  SELECT FLAVOR
                       , SUM(TOTAL_ORDER) AS JULY_ORDER
                    FROM JULY
                GROUP BY FLAVOR
                ) B
             ON A.FLAVOR = B.FLAVOR
       ORDER BY (A.TOTAL_ORDER + B.JULY_ORDER) DESC
       )
 WHERE ROWNUM <= 3

프로그래머스 주문량이 많은 아이스크림들 조회하기 SQL

<MySQL>

SELECT DATE_FORMAT(A.SALES_DATE, '%Y') AS YEAR
     , DATE_FORMAT(A.SALES_DATE, '%c') AS MONTH
     , COUNT(DISTINCT A.USER_ID) AS PUCHASED_USERS
     , ROUND(COUNT(DISTINCT A.USER_ID) / (SELECT COUNT(*) FROM USER_INFO WHERE DATE_FORMAT(JOINED, '%Y') = 2021), 1) AS PUCHASED_RATIO
  FROM ONLINE_SALE A
 INNER JOIN USER_INFO B
    ON A.USER_ID = B.USER_ID
   AND DATE_FORMAT(B.JOINED, '%Y') = 2021
 GROUP BY YEAR, MONTH
 ORDER BY CAST(YEAR AS SIGNED), CAST(MONTH AS SIGNED)

<Oracle>

SELECT EXTRACT(YEAR FROM A.SALES_DATE) AS YEAR
     , EXTRACT(MONTH FROM A.SALES_DATE) AS MONTH
     , COUNT(DISTINCT A.USER_ID) AS PUCHASED_USERS
     , ROUND(COUNT(DISTINCT A.USER_ID) / (SELECT COUNT(*) FROM USER_INFO WHERE TO_CHAR(JOINED, 'YYYY') = 2021), 1) AS PUCHASED_RATIO
  FROM ONLINE_SALE A
 INNER JOIN USER_INFO B
    ON A.USER_ID = B.USER_ID
   AND TO_CHAR(B.JOINED, 'YYYY') = 2021
 GROUP BY EXTRACT(YEAR FROM A.SALES_DATE), EXTRACT(MONTH FROM A.SALES_DATE)
 ORDER BY EXTRACT(YEAR FROM A.SALES_DATE), EXTRACT(MONTH FROM A.SALES_DATE)

프로그래머스 상품을 구매한 회원 비율 구하기 SQL

+ Recent posts