<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개인용 뇌 도서관</title>
    <link>https://nomoreft.tistory.com/</link>
    <description>치열하게 살아간 흔적이 남으면 좋겠다.</description>
    <language>ko</language>
    <pubDate>Sun, 2 Aug 2026 09:26:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>nomoreFt</managingEditor>
    <item>
      <title>자바 알고리즘 부분집합 구하는 방법 CheetSheet</title>
      <link>https://nomoreft.tistory.com/123</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 재귀함수&lt;/b&gt;&lt;/h3&gt;
&lt;div style=&quot;background-color: #222222; color: #f7f1ff;&quot;&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;public static void dfs(int idx,int sum) {
    if(idx &amp;gt;= N){
        if(sum == S) result++;
        return;
    }

    dfs(idx + 1,  sum + arr[idx]);
    dfs(idx + 1,  sum);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고르고 안고른 1/2 의 모든 부분집합을 따져본 방법이다.&lt;/b&gt; [1,2,3,4]가 있을 경우,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;1&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;2&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 3&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(O,X)&amp;nbsp; (O,X) &amp;nbsp; (O,X) &amp;nbsp; (O,X)&amp;nbsp; &amp;nbsp;의 경우를 생각해서 고른 경우와 안고른 경우를 생각해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;public static void dfs(int[] array, int idx, int choiceCnt, String result, int K){
	if(choiceCnt == 6){
    		System.out.println(result);
            return;
        }


    if(idx &amp;gt;= K) return;
    dfs(array, idx + 1, choiceCnt+1, result+array[idx]+&quot; &quot;,K);
    dfs(array, idx + 1, choiceCnt, result,K);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특정 개수에 대한 제한을 걸면 위와 같아지는데,&lt;/b&gt; 고르고 안고른 모든 경우를 따지게 될 때, 특정 개수조건이 충족되면 작업을 수행하고 return 하면 된다. choiceCnt로 몇 개까지 O로 담아놨는지를 체크하는 로직만 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 idx가 끝까지 도달했는데 6개를 담지 못했다면 나가리 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 비트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #222222; color: #f7f1ff;&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;for (int bit = 1; bit &amp;lt; (1 &amp;lt;&amp;lt; N); bit++) {
    int sum = 0;
    for (int k = 0; k &amp;lt; N; k++) {
        if((bit &amp;amp; (1 &amp;lt;&amp;lt; k)) != 0) {
            sum += arr[k];
        }
    }
    if( sum == S) {
        result++;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;nbsp;bit가 1부터 시작하는 이유는&lt;/b&gt; 빈 수열을 나타내는 경우가 &lt;/span&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;bit=0&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;일 때입니다. 빈 수열의 합은 0이므로, 이를 제외하기 위해 &lt;/span&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;bit&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 1부터 시작하게 됩니다. 그래서 1부터 &lt;/span&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;1 &amp;lt;&amp;lt; N&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;까지 반복문을 돌리는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;더 깊게 들어가보면, &lt;/span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;N&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;개의 원소가 있는 배열에서 만들 수 있는 모든 부분수열은 &lt;/span&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;2^N&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt;개입니다.&lt;/b&gt; 그 중 빈 부분수열 1개를 제외한 나머지 &lt;/span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;2^N - 1&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;개의 부분수열을 확인하는 것입니다. 그래서 &lt;/span&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;bit&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 1부터 시작해서 &lt;/span&gt;&lt;span&gt;&lt;span&gt;`&lt;/span&gt;1 &amp;lt;&amp;lt; N&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;까지 반복문을 돌립니다. 이렇게 하면 빈 부분수열을 자연스럽게 제외할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;쉽게 설명하자면, &lt;b&gt;4개의 배열이 있을 때, 선택과 선택하지 않음을 bit (1,0)으로 구분하고, 그 경우의 수를 구하면 2^N이 됩니다.&lt;/b&gt; (OOOO 다 고름, OXOX 2개만 고름) 거기서 4번째 for문에서 4 자리중 불이 켜진 곳이 어딘지 파악해서 원하는 경우를 구하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA 알고리즘/라이브러리화</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/123</guid>
      <comments>https://nomoreft.tistory.com/123#entry123comment</comments>
      <pubDate>Wed, 18 Oct 2023 09:53:38 +0900</pubDate>
    </item>
    <item>
      <title>[등차수열]  백준 등차수열 변환 - 17088</title>
      <link>https://nomoreft.tistory.com/122</link>
      <description>&lt;h1&gt;[Gold V] 등차수열 변환 - 17088&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17088&quot;&gt;문제 링크&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;성능 요약&lt;/h3&gt;
&lt;p&gt;메모리: 27856 KB, 시간: 336 ms&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;브루트포스 알고리즘, 수학&lt;/p&gt;
&lt;h3&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;크기가 N인 수열 A = [A1, A2, ..., AN]이 있을 때, 모든 1 ≤ i &amp;lt; N에 대해서, Ai+1-Ai가 모두 일치하면 등차수열이라고 한다. 예를 들어, [3], [6, 6, 6], [2, 8, 14, 20], [6, 4, 2]는 등차수열이고, [4, 5, 4], [6, 3, 1]은 등차수열이 아니다.&lt;/p&gt;
&lt;p&gt;수열 B = [B1, B2, ..., BN]을 등차수열로 변환하려고 한다. 각각의 수에는 연산을 최대 한 번 적용할 수 있다. 연산은 두 가지가 있는데, 1을 더하거나 1을 빼는 것이다. 수열 B를 등차수열로 변환하기 위해 필요한 연산 횟수의 최솟값을 구해보자.&lt;/p&gt;
&lt;h3&gt;입력&lt;/h3&gt;
&lt;p&gt;첫째 줄에 수열 B의 크기 N(1 ≤ N ≤ 105)이 주어진다. 둘째 줄에는 B1, B2, ..., BN(1 ≤ Bi ≤ 109)이 주어진다.&lt;/p&gt;
&lt;h3&gt;출력&lt;/h3&gt;
&lt;p&gt;수열 B를 등차수열로 변화시키기 위한 연산 횟수의 최솟값을 출력한다. 등차수열로 변환시킬 수 없다면 -1을 출력한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;분석&lt;/h1&gt;
&lt;p&gt;등차수열의 특징을 이용해야 하는 수학 문제다.  &lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;등차수열 : 연속하는 두 항의 차이가 모두 일정한 수열&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;공차를 선정해서 0번째 인덱스부터 공차를 더해 N번까지 가는데 등차에 해당하는 모든 경우를 따져보면 된다.&lt;br&gt;처음에는 문제에서 요구하는 `연산` 이 1을 더하거나 빼는 것이라는 것을 체크하지 못했는데 경우의 수를 줄이는 주요한 포인트이다.&lt;br&gt;문제에서 0, 1번째에서 생성가능한 등차의 경우를 구해서 나머지 모든 경우 O(N) 에서 적용해보면 된다.&lt;br&gt;생성 가능한 등차는 `연산 방법`에 따라 (0번째에 +1, -1, 가만히 둔 경우) * (1번째에 +1, -1, 가만히 둔 경우) = 9가지&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
* 첫 번째 항 -1, 두 번째 항 -1
* 첫 번째 항 -1, 두 번째 항 0
* 첫 번째 항 -1, 두 번째 항 +1
* 첫 번째 항 0, 두 번째 항 -1
* 첫 번째 항 0, 두 번째 항 0
* 첫 번째 항 0, 두 번째 항 +1
* 첫 번째 항 +1, 두 번째 항 -1
* 첫 번째 항 +1, 두 번째 항 0
* 첫 번째 항 +1, 두 번째 항 +1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;공차를 구했다면 Array를 순회하면서 0번째부터 등차를 더한 값과 &lt;code&gt;연산&lt;/code&gt;을 하여 해당 인덱스 값이 같아질 수 있는지 체크하면 된다.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;시간 복잡도는 O(N) 100000 * 9(등차의 경우)라서 900000. 1초 안에 가능하다.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;코드&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import java.io.*;
import java.util.*;


public class Main {

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

        int N = Integer.parseInt(br.readLine());
        int[] arr = Arrays.stream(br.readLine().split(&amp;quot; &amp;quot;))
                .mapToInt(Integer::parseInt)
                .toArray();

        if (N == 1) {
            System.out.println(0);
            System.exit(0);
        }

        int ans = -1;

        for (int i = -1; i &amp;lt;= 1; i++) {
            for (int j = -1; j &amp;lt;= 1; j++) {
                int change = 0;
                if(i != 0) change++;
                if(j != 0) change++;
                int num1 = arr[1] + i;
                int num0 = arr[0] + j;

                //합의된 등차
                int diff = num1 - num0;

                boolean ok = true;
                int target = num0 + diff; //[0]번 + 선택한 등차 = [1]번
                for (int k = 2; k &amp;lt; N; k++) {
                    target += diff; // [1]번 + 등차 = 2번 이후 계속 진행

                    if (arr[k] + 1 == target) {
                        change++;
                    } else if (arr[k] - 1 == target) {
                        change++;
                    } else if (arr[k] == target) {
                        continue;
                    }else{
                        ok = false;
                        break;
                    }
                }
                if (ok) {
                    if (ans == -1 || ans &amp;gt; change) {
                        ans = change;
                    }
                }
            }
        }
        System.out.println(ans);

    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>▾ 01. 기초 알고리즘/▿1. 수학</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/122</guid>
      <comments>https://nomoreft.tistory.com/122#entry122comment</comments>
      <pubDate>Sat, 22 Jul 2023 16:12:35 +0900</pubDate>
    </item>
    <item>
      <title>Java 9 ~ 17까지 도입할만한 유용한 기능과 예시</title>
      <link>https://nomoreft.tistory.com/121</link>
      <description>&lt;h2&gt;Java 9&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;인터페이스의 private 메소드:&lt;/strong&gt; 인터페이스에서도 private 메소드를 선언할 수 있게 되었습니다. 이를 통해 코드의 재사용성을 높일 수 있습니다.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;메소드 구현의 세부 사항 숨기기&lt;/strong&gt;: private 메소드는 인터페이스 외부에서는 접근할 수 없으므로, 메소드의 구현 세부 사항을 숨기고 추상화 수준을 높일 수 있습니다. 이는 캡슐화 원칙을 더 잘 지키는 데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;인터페이스의 안정성 향상&lt;/strong&gt;: private 메소드는 인터페이스의 공개 API의 일부가 아니므로, 이를 변경하더라도 인터페이스를 구현하는 클래스들에게 영향을 미치지 않습니다. 따라서 인터페이스의 안정성을 향상시키는 데 도움이 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public interface MyInterface {
    default void myMethod() {
        helperMethod();
    }

    private void helperMethod() {
        System.out.println(&amp;quot;Helper method in interface&amp;quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Java 10&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;지역 변수의 타입 추론(var):&lt;/strong&gt; 자료형을 명시하지 않아도, 컴파일러가 변수의 타입을 추론할 수 있게 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// Old way
String name = &amp;quot;John&amp;quot;;

// New way
var name = &amp;quot;John&amp;quot;;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Java 11&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;String의 새로운 메소드들: String 클래스에는 &lt;code&gt;isBlank()&lt;/code&gt;, &lt;code&gt;lines()&lt;/code&gt;, &lt;code&gt;strip()&lt;/code&gt;, &lt;code&gt;repeat()&lt;/code&gt; 등 새로운 메소드들이 추가되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;var name = &amp;quot;  John  &amp;quot;;

// Using new methods
System.out.println(name.isBlank());       // false
System.out.println(name.strip());         // &amp;quot;John&amp;quot;
System.out.println(name.repeat(2));       // &amp;quot;  John    John  &amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;Predicate.not 이 생겼습니다. filter시에 부정문으로 제끼기 더 편해졌네요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;List&amp;lt;String&amp;gt; myList = Arrays.asList(&amp;quot;Like,&amp;quot;  &amp;quot;, &amp;quot;Subscribe&amp;quot;);
List&amp;lt;String&amp;gt; withoutBlanks = myList.stream()
                            .filter(Predicate.not(String::isBlank))
                            .collect(Collectors.toList());
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;toArray 메서드가 생겼습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;
List&amp;lt;String&amp;gt; list = Arrays.asList(&amp;quot;Like&amp;quot;,&amp;quot;and&amp;quot;,&amp;quot;Piece&amp;quot;);
String[] array = list.toArray(String[]::new);
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;List의 CopyOf, Collectors.toUnmodifiableList 메서드가 생겼습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; modifiableList = new ArrayList&amp;lt;&amp;gt;();
modifiableList.add(&amp;quot;foo&amp;quot;);
modifiableList.add(&amp;quot;bar&amp;quot;);

List&amp;lt;String&amp;gt; unmodifiableList = List.copyOf(modifiableList);

// 이 코드는 UnsupportedOperationException을 던집니다.
unmodifiableList.add(&amp;quot;baz&amp;quot;);


---------------------------------------------------

List&amp;lt;String&amp;gt; list = Stream.of(&amp;quot;apple&amp;quot;, &amp;quot;banana&amp;quot;, &amp;quot;cherry&amp;quot;)
                                  .collect(Collectors.toUnmodifiableList());

System.out.println(list);

// UnsupportedOperationException을 발생시킵니다.
list.add(&amp;quot;orange&amp;quot;);

&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;불변 리스트의 장점&lt;ul&gt;
&lt;li&gt;외부 코드에 리스트를 전달할 때: unmodifiableList를 사용하면 외부 코드가 리스트를 변경하는 것을 막을 수 있습니다.&lt;/li&gt;
&lt;li&gt;멀티스레드 환경에서 리스트를 공유할 때: unmodifiableList를 사용하면 여러 스레드가 동시에 리스트를 변경하는 것을 방지할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;writeStirng , readString File을 String으로 처리할 수 있게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String file = &amp;quot;java11.txt&amp;quot;
Files.writeString(Paths.get(file), &amp;quot;Geekific&amp;quot;, StandardOpenOption.CREATE);
String content = Files.readString(Paths.get(file));
System.out.println(content);&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Java 12&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Switch Expressions: &lt;code&gt;switch&lt;/code&gt; 문이 표현식으로 사용될 수 있게 되었으며, &lt;code&gt;yield&lt;/code&gt; 키워드를 사용하여 값을 반환할 수 있게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// Old way
String day = &amp;quot;MONDAY&amp;quot;;
switch (day) {
    case &amp;quot;MONDAY&amp;quot;:
        System.out.println(&amp;quot;It&amp;#39;s Monday&amp;quot;);
        break;
    // ... and so on
}

// New way
String day = &amp;quot;MONDAY&amp;quot;;
switch (day) {
    case &amp;quot;MONDAY&amp;quot; -&amp;gt; System.out.println(&amp;quot;It&amp;#39;s Monday&amp;quot;);
    // ... and so on
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Java 13&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;텍스트 블록(Text Blocks): 세 개의 큰 따옴표(&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt;)를 사용하여 멀티 라인 문자열을 표현할 수 있게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;
String text = &amp;quot;&amp;quot;&amp;quot;
              Hello,
              World
              &amp;quot;&amp;quot;&amp;quot;;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;&lt;strong&gt;Java 14&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;instanceof 패턴 매칭: &lt;code&gt;instanceof&lt;/code&gt; 연산자가 패턴 매칭을 지원하게 되어, 캐스팅 없이 조건문을 사용할 수 있게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;
//이전
Person person = new Employee();
if(person instanceof Employee) {
    Employee employee = (Employee) person;
    //형변환 하고 할일 진행
}

//발전

if(person instanceof Employee employee &amp;amp;&amp;amp; employee.getYearsOfService() &amp;gt; 5){
//    employee로 바로 Employee 할 일 진행
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Java 15&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Sealed Classes: 클래스 또는 인터페이스를 특정 타입들에게만 상속 또는 구현을 허용하도록 제한할 수 있게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public sealed interface Shape permits Circle, Rectangle {
    // ...
}

public final class Circle implements Shape {
    // ...
}

public non-sealed class Rectangle implements Shape {
    // ...
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Java 16&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Records: 클래스의 필드, 생성자, getter, &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;, &lt;code&gt;toString()&lt;/code&gt; 등을 자동으로 생성해주는 기능입니다. DTO 나 OpenAPI에서 받아오는 Response 객체 등을 담을 때 유용할 것 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;record Point(int x, int y) { }&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Java 17&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;String indent 메서드. 들여쓰기가 편해집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String text = &amp;quot;test!!!!&amp;quot;
text = text.indent(4); // &amp;quot;    test!!!!&amp;quot;
text = text.indent(-2); // &amp;quot;  test!!!!&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;String transform 메서드. 파라미터 자를때 유용하게 쓸 수 있을 것 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&amp;quot;test!@#$&amp;quot;.transform(value -&amp;gt;
            new StringBuilder(value).delete(4,7).toString());

            //test 반환&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Collectors.teeing 메서드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public static &amp;lt;T,A1,R1,A2,R2,R&amp;gt; Collector&amp;lt;T,?,R&amp;gt; teeing(
    Collector&amp;lt;? super T,A1,R1&amp;gt; downstream1,
    Collector&amp;lt;? super T,A2,R2&amp;gt; downstream2,
    BiFunction&amp;lt;? super R1,? super R2,R&amp;gt; merger
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;* downstream1과 downstream2는 두 개의 다운스트림 컬렉터입니다.
* merger는 두 다운스트림 결과를 결합하는 함수입니다.&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;사용 예시

List&amp;lt;Integer&amp;gt; numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        Integer range = numbers.stream()
                .collect(Collectors.teeing(
                        Collectors.minBy(Integer::compareTo),
                        Collectors.maxBy(Integer::compareTo),
                        (min, max) -&amp;gt; max.orElse(0) - min.orElse(0)
                ));

        System.out.println(&amp;quot;Range: &amp;quot; + range);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발언어/JAVA</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/121</guid>
      <comments>https://nomoreft.tistory.com/121#entry121comment</comments>
      <pubDate>Thu, 20 Jul 2023 16:32:40 +0900</pubDate>
    </item>
    <item>
      <title>코틀린 vs 자바</title>
      <link>https://nomoreft.tistory.com/120</link>
      <description>&lt;p&gt;자바가 있는데 굳이 코틀린을 배워야해? 라고 생각한 뒤, 생각을 고쳐먹고 최근 코틀린을 배우기로 생각했습니다.&lt;br&gt;그래서 코틀린이 자바보다 좋은 이유들을 찾고 있습니다.그것에 대한 정리글입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;간결한 문법&lt;/strong&gt;: Kotlin은 더 간결한 문법을 제공하여 코드를 더 간결하게 작성할 수 있습니다. 예를 들어, Nullable 타입, 확장 함수, 데이터 클래스 등의 기능을 활용하여 코드를 더 간단하고 명확하게 작성할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Java 코드
 String name = &amp;quot;John&amp;quot;;
 if (name != null) {
     System.out.println(name.toUpperCase());
 }

 // Kotlin 코드
 val name: String? = &amp;quot;John&amp;quot;
 println(name?.toUpperCase())&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Null 안전성&lt;/strong&gt;: Kotlin은 타입 시스템에서 Nullable 타입과 Non-Nullable 타입을 명확하게 지원하여 Null 포인터 예외를 방지하는 데 도움을 줍니다. 이로 인해 Null 관련 버그를 줄일 수 있고, 코드의 안정성을 향상시킬 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Java 코드
 String name = null;
 System.out.println(name.length()); // NullPointerException 발생

 // Kotlin 코드
 val name: String? = null
 println(name?.length) // null 출력&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;확장 함수&lt;/strong&gt;: Kotlin은 확장 함수를 지원하여 기존 클래스의 기능을 확장할 수 있습니다. 이는 기존 클래스의 코드 수정 없이 새로운 함수를 추가할 수 있는 장점을 제공합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Java 코드
 StringUtils.capitalize(&amp;quot;hello&amp;quot;); // 외부 클래스의 정적 메서드 호출

 // Kotlin 코드
 &amp;quot;hello&amp;quot;.capitalize() // String 클래스에 capitalize() 함수 추가&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;함수형 프로그래밍 지원&lt;/strong&gt;: Kotlin은 함수형 프로그래밍의 개념과 기능을 지원합니다. 람다 식, 고차 함수, 스트림 처리 등을 활용하여 코드를 더욱 간결하고 효율적으로 작성할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Java 코드
 List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5);
 int sum = 0;
 for (int num : numbers) {
     sum += num;
 }
 System.out.println(sum);

 // Kotlin 코드
 val numbers = listOf(1, 2, 3, 4, 5)
 val sum = numbers.sum()
 println(sum)&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;strong&gt;자바 호환성&lt;/strong&gt;: Kotlin은 100% 자바와 상호 운용이 가능합니다. 기존의 자바 코드와 라이브러리를 Kotlin으로 전환하거나 Kotlin 코드를 자바와 함께 사용하는 것이 매우 쉽습니다. 이는 기존 자바 프로젝트에서 점진적으로 Kotlin을 도입할 수 있음을 의미합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;위의 예시 코드에서 볼 수 있듯이, Kotlin은 코드를 더 간결하고 안전하게 작성할 수 있도록 도와줍니다. 이를 통해 생산성을 향상시키고 버그를 줄이는 데 도움이 됩니다. 또한, Kotlin은 Java와의 상호 운용성을 제공하여 기존 자바 코드와 라이브러리를 쉽게 활용할 수 있습니다.&lt;/p&gt;</description>
      <category>개발언어/KOTLIN</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/120</guid>
      <comments>https://nomoreft.tistory.com/120#entry120comment</comments>
      <pubDate>Tue, 18 Jul 2023 18:09:05 +0900</pubDate>
    </item>
    <item>
      <title>알고리즘에서 비트마스크로 경우의 수 따지는 방법</title>
      <link>https://nomoreft.tistory.com/119</link>
      <description>&lt;p&gt;때로 브루트포스에서 경우의 수 (부분집합)를 따지는 상황이 왕왕 발생한다.&lt;/p&gt;
&lt;p&gt;그런 상황에서 요긴하게 쓰이는 bitmask로 경우의 수 따지기, 유용한 상황 처리에 대해서 정리하려고 한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;비트마스크(Bitmask)는?&lt;/h2&gt;
&lt;h3&gt;이진수로 표현된 비트들의 집합으로, 각 비트가 특정 상태를 나타냅니다. 비트마스크를 사용하면 집합의 부분집합을 효과적으로 나타낼 수 있고, 이를 활용하여 경우의 수를 따질 수 있습니다.&lt;/h3&gt;
&lt;h3&gt;기본적인 사용법&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public class BitmaskExample {
    public static void main(String[] args) {
        int n = 3; // 비트 수
        int total = 1 &amp;lt;&amp;lt; n; // 총 경우의 수: 2^n

        for (int i = 0; i &amp;lt; total; i++) {
            for (int j = 0; j &amp;lt; n; j++) {
                if ((i &amp;amp; (1 &amp;lt;&amp;lt; j)) &amp;gt; 0) {
                    // j번째 비트가 1인 경우의 처리
                    System.out.print(1);
                } else {
                    // j번째 비트가 0인 경우의 처리
                    System.out.print(0);
                }
            }
            System.out.println(); // 한 줄 출력 후 개행
        }
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;1.각 비트를 사용, 사용X의 상태로 생각 :&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; 예를들어 int[] A = {1,2,3} 이라면 123의 부분집합을 구하여 문제에서 주어진 경우의 수를 따질 수 있다. &lt;/p&gt;
&lt;p&gt; -&amp;gt; 예를 들어 3개의 비트를 사용한다면, 000,001,010,011,100,101,110,111 과 같이 2^3 = 8가지의 상태를 나타낼 수 있다.&lt;/p&gt;
 &lt;br&gt;

&lt;p&gt;&lt;strong&gt;2. 비트 연산을 통한 조합 :&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;비트 연산을 사용해 특정 경우가 사용되고 있는지, 내가 원하는 비트가 켜져 있는지 체크하여 경우의 수를 고려할 수 있다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; &amp;amp; (AND), | (OR), ^(XOR) , ~ (NOT) 연산을 사용한다.&lt;/p&gt;
&lt;br&gt;

&lt;hr&gt;
&lt;br&gt;

&lt;h2&gt;예시&lt;/h2&gt;
&lt;p&gt;괄호 추가하기 : &lt;a href=&quot;https://www.acmicpc.net/problem/16637&quot;&gt;https://www.acmicpc.net/problem/16637&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;


&lt;p&gt;괄호 추가하기의 문제로 3+8&lt;em&gt;7-9&lt;/em&gt;2 식의 수식이 주어지면 연속된 괄호 없이 모든 괄호를 치는 &amp;#39;경우의 수&amp;#39; 를 따져서 최대 계산 값을 따지는 문제이다.&lt;/p&gt;
&lt;br&gt;

&lt;p&gt;이 문제에서는 괄호가 연속으로 쳐지면 안된다. 따라서 우리는 비트마스크를 사용하여 괄호를 적용할 위치의 부분집합을 나타내고, 이를 통해 가능한 모든 경우의 수를 구하게 된다.&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;


&lt;p&gt;다음과 같은 경우를 예로 들어보겠습니다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(3+8)&lt;em&gt;(7-9)&lt;/em&gt;2 의 경우는 가능&lt;/li&gt;
&lt;li&gt;((3+8)&lt;em&gt;7)-9&lt;/em&gt;2 의 경우 불가능. 중첩 괄호 X&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
        int cnt = 수식의 수 4


//(+ , *, -, * ) 의 부분집합들로 모든 경우의 수를 찾는다.
        for (int bit = 0; bit &amp;lt; (1 &amp;lt;&amp;lt; cnt); bit++) {
            boolean ok = true;

        //각 경우마다 내부에서 0,1,2,3번째 개체가 들어갔나 체크하기 위해 반복한다.
            for(int i = 0; i &amp;lt; m - 1; i++) {
                //지금 부분집합 (bit) 에서 지금과 다음 수식에 괄호가 함께 쓰이면 패스한다.
                if((bit &amp;amp; (1 &amp;lt;&amp;lt; i)) &amp;gt; 0 &amp;amp;&amp;amp; (bit &amp;amp; (1 &amp;lt;&amp;lt; (i + 1))) &amp;gt; 0) {
                    ok = false;
                    break;
                }
            }
            if(!ok) continue;

            //하고 싶은 작업

         }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Java 코드&lt;/strong&gt;에서는 먼저 수식의 개수를 기반으로 부분집합을 나타내는 bit를 설정합니다.&lt;br&gt;이후 모든 부분집합에 대해, &lt;strong&gt;연속된 두 수식에 동시에 괄호가 적용&lt;/strong&gt;되어 있는지 검사합니다.&lt;br&gt;이 경우, 괄호가 연속해서 적용되어 있으므로 해당 부분집합은 배제하고, 그렇지 않은 경우에만 계산을 진행하게 됩니다.&lt;br&gt;이 방법을 통해 연속된 괄호 없이 모든 괄호를 적용할 수 있는 경우의 수를 구할 수 있습니다.&lt;/p&gt;</description>
      <category>▾ 03. 고급 알고리즘/▿1. 비트마스크</category>
      <category>bitmask</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/119</guid>
      <comments>https://nomoreft.tistory.com/119#entry119comment</comments>
      <pubDate>Tue, 18 Jul 2023 18:00:46 +0900</pubDate>
    </item>
    <item>
      <title>Java에서 효율적인 경우의 수 따지기</title>
      <link>https://nomoreft.tistory.com/118</link>
      <description>&lt;h1&gt;C++의 next_permutation 구현&lt;/h1&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;static boolean next_permutation(int[] a) {
        int i = a.length-1;
        while (i &amp;gt; 0 &amp;amp;&amp;amp; a[i-1] &amp;gt;= a[i]) {
            i -= 1;
        }

        if (i &amp;lt;= 0) {
            return false;
        }

        int j = a.length-1;
        while (a[j] &amp;lt;= a[i-1]) {
            j -= 1;
        }

        int temp = a[i-1];
        a[i-1] = a[j];
        a[j] = temp;

        j = a.length-1;
        while (i &amp;lt; j) {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
            i += 1;
            j -= 1;
        }
        return true;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실사용 예시&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경우의 수를 구하고 싶은 List의 숫자만큼 d[i] 로 Array를 구현한 다음, 해당 d[i] 를 next_permutation 돌린다.&lt;br /&gt;do-while로 nextPermuation을 사용하는 모습. bitMask를 구현한 것과 같다&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;        int[] d = new int[store.size()];
        for (int i=0; i&amp;lt;m; i++) {
            d[i] = 1;
        }
        Arrays.sort(d);
        int ans = -1;
        do {
            int sum = 0;
            for (Pair p : people) {
                int min = -1;
                for (int i=0; i&amp;lt;store.size(); i++) {
                    if (d[i] == 0) continue;
                    Pair s = store.get(i);
                    int d1 = p.first-s.first;
                    int d2 = p.second-s.second;
                    if (d1 &amp;lt; 0) d1 = -d1;
                    if (d2 &amp;lt; 0) d2 = -d2;
                    int dist = d1+d2;
                    if (min == -1 || min &amp;gt; dist) {
                        min = dist;
                    }
                }
                sum += min; 
            }
            if (ans == -1 || ans &amp;gt; sum) {
                ans = sum;
            }
        } while (next_permutation(d));&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;code&gt;순열&lt;/code&gt; 재귀함수 백트래킹으로 구현하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 애용하는 방법. start index를 이용해서 경우의 수가 반복되지 않게 한방향으로 모든 순열의 경우를 구할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;    static void go(int idx, String sum) {
        if (idx == n) {
            System.out.println(sum);
        }

        //전체 순열이라 매 숫자 Choice시에 전체 경우중 선택하지 않은 것 고려
        for(int i = 0; i &amp;lt; n; i++) {
            if(visited[i]) continue;
            //0으로 시작하는 숫자는 제외할 경우
            if(idx == 0 &amp;amp;&amp;amp; A[i]== 0) continue;
            visited[i] = true;
            go( idx + 1, sum + A[i]);
            visited[i] = false;
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-08-23 094141.png&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQAHyd/btsrTOr8RlQ/klobBrqgkNHfGKqJmlIghk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQAHyd/btsrTOr8RlQ/klobBrqgkNHfGKqJmlIghk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQAHyd/btsrTOr8RlQ/klobBrqgkNHfGKqJmlIghk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQAHyd%2FbtsrTOr8RlQ%2FklobBrqgkNHfGKqJmlIghk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;538&quot; data-filename=&quot;화면 캡처 2023-08-23 094141.png&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 모든 경우의 수 중에서 특정 조건을 충족하는 것들을 추출해낼 때 사용한다.&lt;/p&gt;
&lt;h1&gt;&lt;code&gt;조합&lt;/code&gt; 재귀함수 백트래킹으로 구현하기&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Main {
    static int[] A = {1,2,3,4};
    static boolean visited[] = new boolean[4];
    public static void main(String[] args) {
        go(0,0,&quot;&quot;);
    }

    private static void go(int idx, int start, String sum) {
        if (idx == 3) {
            System.out.println(sum);
            return;
        }

        for (int i = start; i &amp;lt; 4; i++) {
            if (visited[i]) continue;
            visited[i] = true;
            go(idx + 1, i + 1, sum + A[i]); // 현재 인덱스 다음부터 시작
            visited[i] = false;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-08-23 094200.png&quot; data-origin-width=&quot;68&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MoasW/btsrYN7jiZQ/dL9AzFeoht9WYO9nnCqnxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MoasW/btsrYN7jiZQ/dL9AzFeoht9WYO9nnCqnxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MoasW/btsrYN7jiZQ/dL9AzFeoht9WYO9nnCqnxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMoasW%2FbtsrYN7jiZQ%2FdL9AzFeoht9WYO9nnCqnxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;68&quot; height=&quot;91&quot; data-filename=&quot;화면 캡처 2023-08-23 094200.png&quot; data-origin-width=&quot;68&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로또같은 것들은 49개의 숫자중에서 중복되지 않게 6개를 골라야 하는 경우다. 모든 로또의 경우는 순열이 아니라 조합이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;bit로 경우의 수 구하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 부분집합을 구할 때 편하다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;
public class Main {
    static int[] A = {1,2,3,4};
    static boolean visited[] = new boolean[4];
    public static void main(String[] args) {

        for (int bit = 0; bit &amp;lt; (1 &amp;lt;&amp;lt; 4); bit++) {//2의 4승으로 4가지 배열의 모든 on/off를 고려
            String sum = &quot;&quot;;
            for (int i = 0; i &amp;lt; 4; i++) {//각 비트 자리수를 확인 ( ㅇ ㅇ ㅇ ㅇ )
                if ((bit &amp;amp; (1 &amp;lt;&amp;lt; i)) != 0) {//i번째 비트가 1이면 i번째 원소 출력
                    sum += A[i];
                }
            }
            System.out.println(sum);

        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-08-23 094906.png&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rvb6Q/btsrR495Ala/OGhAbCxVdqhdLF9iOYDTC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rvb6Q/btsrR495Ala/OGhAbCxVdqhdLF9iOYDTC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rvb6Q/btsrR495Ala/OGhAbCxVdqhdLF9iOYDTC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frvb6Q%2FbtsrR495Ala%2FOGhAbCxVdqhdLF9iOYDTC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;178&quot; height=&quot;352&quot; data-filename=&quot;화면 캡처 2023-08-23 094906.png&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;bit로 부분집합 구하기&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Main {
    static int[] A = {1,2,3,4};
    static boolean visited[] = new boolean[4];
    public static void main(String[] args) {

        for (int bit = 0; bit &amp;lt; (1 &amp;lt;&amp;lt; 4); bit++) {//2의 4승으로 4가지 배열의 모든 on/off를 고려
            String sum = &quot;&quot;;
            int cnt = 0;
            for (int i = 0; i &amp;lt; 4; i++) {//각 비트 자리수를 확인 ( ㅇ ㅇ ㅇ ㅇ )
                if ((bit &amp;amp; (1 &amp;lt;&amp;lt; i)) != 0) {//i번째 비트가 1이면 i번째 원소 출력
                    cnt++;
                    sum += A[i];
                }
            }

            if(cnt == 2) System.out.println(sum);

        }
    }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-08-23 095020.png&quot; data-origin-width=&quot;56&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5mm0x/btsrVtnIkYL/1X6R4nr5FkILH8nZG6pMOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5mm0x/btsrVtnIkYL/1X6R4nr5FkILH8nZG6pMOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5mm0x/btsrVtnIkYL/1X6R4nr5FkILH8nZG6pMOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5mm0x%2FbtsrVtnIkYL%2F1X6R4nr5FkILH8nZG6pMOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;56&quot; height=&quot;133&quot; data-filename=&quot;화면 캡처 2023-08-23 095020.png&quot; data-origin-width=&quot;56&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘의 최우선 고려대상은 브루트포스 (전체 탐색) 으로 가능한지, 아닌지이다. 지금까지 경우의 수를 구하는 다양한 방법을 알아봤는데 이 경우의 수 틀에서 문제에 맞게 사용하면 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;code&gt;bit vs 재귀&lt;/code&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트 연산을 사용한 방법과 재귀를 사용한 방법은 각각의 상황에서 장단점이 있을 수 있다. 지금의 경우, 4개의 원소에서 2개를 선택하는 조합을 구하는 상황이므로 성능 차이는 거의 나지 않을 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;비트 연산:&lt;br /&gt;장점: 코드가 간결하고, 직관적입니다.&lt;br /&gt;단점: 문제의 규모가 커지면 비트 연산을 사용할 수 없는 경우가 발생할 수 있습니다. (32비트나 64비트 제한 등)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;재귀 호출:&lt;br /&gt;장점: 문제의 규모가 커져도 유연하게 대처할 수 있으며, 더 복잡한 문제에도 적용할 수 있습니다.&lt;br /&gt;단점: 코드가 조금 더 복잡하고, 재귀 호출에 따른 오버헤드가 있을 수 있습니다.&lt;br /&gt;그럼에도 불구하고, 위와 같은 작은 문제에서는 두 방법 모두 거의 동일한 성능을 보일 것입니다. 어떤 방식을 사용할지는 주로 코드의 가독성, 유지보수성, 확장성 등을 고려하여 결정하게 됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때에 따라서는 두 가지 방식을 혼합해서 사용하는 것도 좋은 방법이 될 수 있으니, 문제의 특성과 요구사항에 맞게 선택하면 된다.&lt;/p&gt;</description>
      <category>JAVA 알고리즘/라이브러리화</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/118</guid>
      <comments>https://nomoreft.tistory.com/118#entry118comment</comments>
      <pubDate>Fri, 14 Jul 2023 15:25:15 +0900</pubDate>
    </item>
    <item>
      <title>인접 리스트</title>
      <link>https://nomoreft.tistory.com/117</link>
      <description></description>
      <category>▾ 02. 중급 알고리즘/▿6. DFS, BFS</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/117</guid>
      <comments>https://nomoreft.tistory.com/117#entry117comment</comments>
      <pubDate>Fri, 14 Jul 2023 15:24:23 +0900</pubDate>
    </item>
    <item>
      <title>인접 행렬</title>
      <link>https://nomoreft.tistory.com/116</link>
      <description></description>
      <category>▾ 02. 중급 알고리즘/▿6. DFS, BFS</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/116</guid>
      <comments>https://nomoreft.tistory.com/116#entry116comment</comments>
      <pubDate>Fri, 14 Jul 2023 15:24:09 +0900</pubDate>
    </item>
    <item>
      <title>플로이드 와샬 알고리즘</title>
      <link>https://nomoreft.tistory.com/115</link>
      <description></description>
      <category>▾ 03. 고급 알고리즘/▿4. 최단 경로 알고리즘</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/115</guid>
      <comments>https://nomoreft.tistory.com/115#entry115comment</comments>
      <pubDate>Fri, 14 Jul 2023 15:23:37 +0900</pubDate>
    </item>
    <item>
      <title>벨만 포드 알고리즘</title>
      <link>https://nomoreft.tistory.com/113</link>
      <description></description>
      <category>▾ 03. 고급 알고리즘/▿4. 최단 경로 알고리즘</category>
      <author>nomoreFt</author>
      <guid isPermaLink="true">https://nomoreft.tistory.com/113</guid>
      <comments>https://nomoreft.tistory.com/113#entry113comment</comments>
      <pubDate>Fri, 14 Jul 2023 15:23:10 +0900</pubDate>
    </item>
  </channel>
</rss>