function Memo({ item, Delete, Edit, SetPosition, SetWidthHeight }) {
  const handleRef = useRef(null);

  return (
    <Draggable handleRef={handleRef} x={0} y={0} onMove={(x,y) => console.log(x,y)}>
    <div
      className="memo-container"
      style={{ width: `${250}px`, height: `${300}px` }}
    >
      <div className="menu">
        <DragHandleIcon 
          ref={handleRef}
          sx={{ cursor: "move", fontSize: "25px" }} />
        <CloseIcon
          sx={{ cursor: "pointer", fontSize: "25px", float: "right" }}
        />
      </div>
      <textarea
        className="memo-text-area"
        defaultValue={"Enter memo here"}
        name="txt"
        placeholder="Enter memo here"
      ></textarea>
    </div>
    </Draggable>
  );
}

 

위와 같이 Draggable 커스텀 컴포넌트를 사용하는데 아래와 같은 오류가 발생했다.

 

오류의 원인은 3가지 정도가 있다고 한다.

 

  • react, renderer 버전
    • react-dom 버전이 16.8.0 이하인 경우 발생할 수 있으나 현재 사용하고 있는 버전이 18.1.0 이기 때문에 해당되지 않음
  • Hooks 규칙 위반
    • 컴포넌트 내에서 훅 함수를 사용했기 때문에 문제 없어보인다.
  • 동일 앱에 1개 이상의 리액트 
    • 즉 오류의 원인은 여기인 듯 함. 자세히 살펴보자

 

Draggable 컴포넌트를 사용하기 위해 다운받았던 @billy-fe/draggable@1.0.2 패키지에서 react 버전 17.0.2에 종속되어 있는 것을 확인할 수 있다. 필자는 현재 18.1.0을 사용하고 있는데, 일부 패키지에서 17.0.2에 종속되어 있기 때문에 이러한 오류가 발생한 듯 하다.

 

 

해당 라이브러리 폴더(@billy-fe/draggable)로 이동 후 npm link를 이용해서 해결

npm link는 아직 잘 모르지만, 해당 라이브러리의 리액트를 프로젝트의 리액트로 연결하는 기능 같음.

 

 

npm link C:\workspace/sticker-memo/node_modules/react

 

 

참고

https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react

 

소수하기

이번 포스팅 문제는 1929번 문제입니다.


문제요약

에라토스테네스의 체 알고리즘을 이용하여 자연수 M이상 N이하의 소수를 출력하는 문제입니다.

풀이전략



구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package BackJoon.수학;
 
import java.util.Scanner;
 
/**
 * https://www.acmicpc.net/problem/1929
 * 에라토스테네스의 체
 * @author troh
 */
public class _1929_소수구하기 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int num1 = sc.nextInt();
        int num2 = sc.nextInt();
        
        boolean[] check = new boolean[num2+1];
        for(int i=2; i<=num2; i++) {
            if(!check[i]) {
                for(int j=i+i; j<=num2; j=j+i) {
                    check[j] = true;
                }
            }
        }
        
        int count = 0;
        for(int i=num1; i<=num2; i++) {
            if(i == 1continue;
            
            if(!check[i]) {
                System.out.println(i);
            }
        }
    }
}
 
cs

배운점

에라토스테네스의 체

에라토스테네스의 체

에라토스테네스의 체 알고리즘은 소수를 구할 때 사용할 수 있는 알고리즘 입니다.


알고리즘 

  1. 2부터 소수를 구하고자 하는 구간의 모든 수를 나열한다.

  2. 2는 소수이므로 자기자신을 제외한 2의 배수를 모두 지웁니다.

  3. 다음 남아있는 수(3)은 소수이므로 자기자신을 제외한 3의 배수를 모두 지웁니다.

  4. 다음 남아있는 수(5)는 소수이므로 자기자신을 제외한 5의 배수를 모두 지웁니다

  5. 위와 같은 작업을 10까지 반복했을 때 지워지지않고 남아있는 모든수가 소수입니다.

그렇다면 왜 10까지만 반복하는 걸까 ?  
  1. 2를 가지고 위의 작업을 수행하면 2*2, 2*3, 2*4, 2*5... 2*50까지 지워집니다.
  2. 다음으로 3을 가지고 작업한다고 했을 때 3*2, 3*3, 3*4, 3*5 .. 3*33까지 지워집니다.
  3. 다음으로 5로 수행했을 때 5*2, 5*3, 5*4, 5*5, 5*6... 5*20까지 지워집니다.

3의 배수를 지운다고 했을 때 3*2는 이미 2의 배수이기 때문에 지워지고

5의 배수를 지운다고 했을 때 5*2, 5*3, 5*4는 이미 2 또는 3의 배수여서 지워졌기 때문에 비교의 의미가 없습니다.


즉 11로 위의 작업을 수행한다고 가정한다면 11*10 이하의 자연수에서 소수가 아닌 수들은 이미 다 지워졌기 떄문에 위의 작업은 10까지만 수행하는 것입니다.


구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package BackJoon.수학;
 
import java.util.Scanner;
 
/**
 * 에라토스테네스의 체
 * @author troh
 */
public class Main{
    public static void main(String[] args) {
        boolean[] check = new boolean[101];
        
        // 소수의 배수를 모두 체크
        for(int i=2; i<=10; i++) {
            if(!check[i]) {
                for(int j=i+i; j<101; j=j+i) {
                    check[j] = true;
                }
            }
        }
        
        // 소수출력
        for(int i=1; i<=100; i++) {
            if(i == 1continue;
            
            if(!check[i]) {
                System.out.println(i);
            }
        }
    }
}
cs


이번 포스팅 문제는 9613번 문제입니다


문제요약

양의 정수 n개가 주어졌을 때 가능한 모든 쌍의 GCD의 합을 구하는 문제


풀이전략

양의 정수n개가 다음과 같이 {10, 20, 30, 40} 이렇게 주어졌다면 
  1. 10과 {20, 30, 40} 의 GCD를 각각 구해서 결과값에 더함
  2. 20과 {30, 40} 의 GCD를 각각 구해서 결과값에 더함
  3. 30과 {40}의 GCD를 구해서 결과값에 더함

구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package BackJoon.수학;
 
import java.util.Scanner;
 
/**
 * https://www.acmicpc.net/problem/9613
 * @author troh
 */
public class _9613_GCD합 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 테스트 횟수
        int c = sc.nextInt();
        
        for(int i=0; i<c; i++) {
            // 입력받을 정수 개수
            int s = sc.nextInt();
            
            // 정수 입력
            int[] arr = new int[s];
            for(int j=0; j<s; j++) {
                arr[j] = sc.nextInt();
            }
            
            // gcd 합 출력
            System.out.println(sumGcd(arr));
        }
    }
    
    private static long sumGcd(int[] arr) {
        long sum = 0;
        for(int i=0; i<arr.length-1; i++) {
            for(int j=i+1; j<arr.length; j++) {
                sum += gcd(arr[i], arr[j]);
            }
        }
        return sum;
    }
    
    private static int gcd(int a, int b) {
        if(b == 0
            return a;
        else
            return gcd(b, a%b);
    }
}
 
cs

배운점

자연수 A, B 최소공배수(GCD)를 구하는 알고리즘을 알게되었다. 

스택 수열

이번 포스팅 문제는 1874번 문제입니다.


문제요약

문제에서는 수열이 주어지는데 이 수열을 스택으로 만들 수 있는지 없는지를 판단하는 문제입니다. 
예를 들어 {4, 3, 6, 8, 7, 5, 2, 1} 수열이 주어지고 스택에 삽입하는 수는 1부터 순차적으로 증가될 때 이 수열이 스택을 이용해서 어떻게 만들어지는지 알아보도록 하겠습니다.


풀이전략

  1. 수열원소 > 자연수라면 "자연수 == 원소"일 때 까지  스택에 push() 합니다
  2. 수열원소 < 자연수라면 이미 스택에 수열원소가 들어가 있다는 뜻입니다. 그럼 스택에서 pop()을 수행하여 수열원소를 찾습니다.
    하지만 이 때 "pop()에서 얻은 값이 != 수열원소"라면 해당 수열은 스택으로 만들 수 없는 수열을 뜻합니다. 왜냐하면 스택은 LIFO 구조이기 때문에 최상단 아래 원소를 구할 수 없기 때문입니다.

구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package BackJoon.스택;
 
import java.util.Scanner;
import java.util.Stack;
 
public class _1874_스택수열 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int T = sc.nextInt();
        int[] arr = new int[T];
        for(int i=0; i<T; i++) {
            arr[i] = sc.nextInt();
        }
        
        String s = getSolution(arr);
        System.out.println(s);
    }
    
    private static String getSolution(int[] arr) {
        Stack<Integer> stack = new Stack<>();
        StringBuffer bf = new StringBuffer();
        int num = 1// 자연수
        for(int i=0; i<arr.length; i++) {
            int e = arr[i]; // 만들어야 하는 수열요소
            
            // 자연수가 만들어야하는 요소보다 작을 때
            if(num <= e) {
                while(num <= e) {
                    // 자연수를 증가시키며 스택에 추가
                    stack.push(num++);
                    bf.append("+\n");
                    
                    // 만들어야하는 요소까지 스택에 담았다면 꺼냄
                    if(num > e) {
                        stack.pop();
                        bf.append("-\n");
                    }
                }
            } 
            // 자연수가 만들어야하는 요소보다 클 때 -> 만들어야하는 요소는 이미 스택에 들어있다는 의미
            else {
                int n = stack.pop();
                // 스택의 가장 위의 수(n)가 만들어야하는 요소(e)보다 크다면 pop() 을 했을 때 n이 출력되므로 요소를 출력할 수 없음
                if(n > e) {
                    return "NO";
                } //  
                else {
                    bf.append("-\n");
                }
            }
        }
        return bf.toString();
    }
}
 
cs

배운점

알고리즘을 생각하는 것보다 알고리즘을 코드로 옮기는게 역시나 훨씬 어려웠습니다. 전반적인 알고리즘을 구현해놓고 제약사항(인덱스의 마지막 등)을 상세하게 구현해주는게 문제 푸는게 좀 더 수월한 것 같습니다 

괄호

이번 포스팅 문제는 9012번 입니다. 이번 문제 역시 스택을 이용하여 풀이하였습니다.

문제요약

주어진 문자열이 올바른 괄호인지 판단하는 문제입니다. 올바른 괄호란 여는 괄호, 닫는 괄호의 순서와 수량이 같은 괄호를 말합니다.

풀이전략

그럼 올바른 괄호를 판단하는 기준을 생각해보겠습니다. 
  1. 여는 괄호와 닫는 괄호의 개수가 같아야 합니다.
  2. 여는 괄호와 닫는 괄호의 순서가 올바라야 합니다
    1. 닫는 괄호가 나왔을 때 이전 여는 괄호 중에서 가장 가까운 괄호와 매핑된다.
    2. 닫는 괄호가 나왔을 때 이전 여는 괄호 중에서 매핑되지 않은 여는 괄호가 하나이상 존재해야 한다.
그럼 스택을 이용한 풀이 전략을 짜보도록 하겠습니다.
  1. 주어진 문자열을 문자 배열로 변환합니다
  2. 배열을 순회하며 여는 괄호라면 스택에 담고 닫는 괄호라면 스택의 내용을 추출한다. 
    이 때, 스택의 내용을 추출하려고 할 때 스택이 비어있다면 순서 또는 개수가 맞지 않으므로 올바른 괄호가 아님을 알 수 있습니다.
  3. 배열을 모두 순회하였을 때 스택이 비어있다면 올바른 괄호이며 비어있지 않다면 개수가 맞지 않으므로 올바른 괄호가 아님을 알 수 있습니다.

구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package BackJoon.스택;
 
import java.util.Scanner;
import java.util.Stack;
 
public class _9012_괄호 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int T = sc.nextInt();
        sc.nextLine();
        
        for(int i=0; i<T; i++) {
            String s = sc.nextLine();
            String solution = getSolution(s);
            System.out.println(solution);
        }
    }
    
    private static String getSolution(String s) {
        char[] charArr = s.toCharArray();
        
        Stack<Character> stack = new Stack<>();
        for(int i=0; i<charArr.length; i++) {
            char c = charArr[i];
            // 여는 괄호라면 스택에 추가
            if(c == '(') {
                stack.push(c);
            } // 닫는 괄호라면 스택에서 꺼냄 
            else if(c == ')') {
                // 꺼낼 여는 괄호가 없다면 여는 괄호와 닫는 괄호 순서가 맞지않음
                if(stack.isEmpty()) {
                    return "NO";
                }
                stack.pop();
            }
        }
        // 스택이 비어있지않다면 여는 괄호와 닫는괄호 갯수가 맞지않음
        return stack.isEmpty() ? "YES" : "NO";
    }
}
 
cs

배운점

스택을 사용한 가장 큰 이유는 "닫는 괄호가 나왔을 때 가장 가까운 여는 괄호와의 매핑" 이였습니다. 스택의 성질중 가장 마지막에 삽입한 원소가

가장 먼저 추출된다는 성질이 있기때문에 적합하다고 판단하였습니다. 

단어 뒤집기

이번 포스팅 문제는 9093번 문제입니다. 이 문제는 스택의 성질을 이용하여 풀이하였습니다.

스택은 LIFO(Last In First Out) 성질 즉, 마지막 넣은 요소를 처음으로 얻을 수 있다는 것입니다. 자 이 성질을 염두에 두고 문제를 풀어보도록 하겠습니다.


문제요약

주어진 문장에서 단어(띄어쓰기로 구분)단위로 단어를 뒤집으면서 출력하는 문제입니다. 예를 들어
"I am happy today" 는 4개의 단어 I, am, happy, today로 나누어지고 이 4단어를 각각 역순으로 출력하면 "I ma yppah yadot" 이 출력됩니다.

풀이전략

  1. 주어진 문장을 Charactor형 공백을 포함한 배열로 변환합니다.
  2. 배열을 순회하면서 만난 요소가 공백이 아니라면 스택에 추가를, 공백 또는 문장의 마지막을 나타낸다면 스택의 내용을 모두 출력합니다.

구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package BackJoon;
 
import java.io.IOException;
import java.util.Scanner;
import java.util.Stack;
 
/**
 * https://www.acmicpc.net/problem/9093
 * @author troh
 *
 */
public class _9093_단어뒤집기 {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        
        int t = sc.nextInt();
        sc.nextLine();
        
        String[] inputs = new String[t];
        for(int i=0; i<t; i++) {
            inputs[i] = sc.nextLine();
        }
        
        for(int i=0; i<inputs.length; i++) {
            String s = getSolution(inputs[i]);
            System.out.println(s);
        }
    }
    
    private static String getSolution(String s) {
        s += '\n';
        Stack<Character> stack = new Stack<>(); 
        StringBuffer bf = new StringBuffer();
        for(int i=0; i<s.length(); i++) {
            if(s.charAt(i) == ' ' || s.charAt(i) == '\n') {
                while(!stack.isEmpty()) {
                    bf.append(stack.pop());
                }
                if(i != s.length()-1) {
                    bf.append(s.charAt(i));
                }
            } else {
                stack.push(s.charAt(i));
            }
        }
        return bf.toString();
    }
}
 
cs

배운점

문제에서 공백 또한 포함한 출력결과를 만들어야하기 때문에 입력받은 문자열에 '\n'을 임의로 추가해주고 문자열의 끝을 체크했습니다. 하지만 '\n'은 개행문자 이기때문에 출력결과에는 포함되지 않도록 만들었습니다.  씨언어에서는 문자열의 끝에 널문자가 포함되는 것으로 기억하는데 씨언어로 구현할 수 있다면 좀 더 편할 것 같네요..ㅎㅎ 


아무튼 스택의 성질은 무언가를 뒤집을 때 사용하면 좋을 것 같습니다. 






삽입정렬

자신의 위치를 찾아 삽입함으로써 정렬하는 알고리즘입니다

알고리즘 이해하기

배열의 두번째 요소부터 진행하며 그 앞쪽의 자료들과 비교하며 자신의 위치를 찾아 삽입하며 삽입이 완료되면 다음 요소부터 과정을 반복합니다.
{3, 5, 2, 1, 4} 를 정렬하는 모습을 살펴보겠습니다..


알고리즘 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.Scanner;
 
public class Sort {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int count = sc.nextInt();
        int[] arr = new int[count];
        
        for(int i=0; i<count; i++) {
            arr[i] = sc.nextInt();
        }
        
        arr = sort(arr);
        for(int i=0; i<count; i++) {
            System.out.println(arr[i]);
        }
    }
    
    private static int[] sort(int[] arr) {
        for(int i=1; i<arr.length; i++) {
            for(int j=i; j>=1; j--) {
                if(arr[j-1> arr[j]) {
                    int temp = arr[j];
                    arr[j] = arr[j-1];
                    arr[j-1= temp;
                }
            }
        }
        return arr;
    }
}
 
cs


'알고리즘 > 정렬' 카테고리의 다른 글

버블정렬(Bubble Sort)  (0) 2019.09.07

+ Recent posts