반응형

 

 

 

 

 

풀이코드

public class Solution {
    public string solution(string s) {
        char[] charArr = s.ToLower().ToCharArray();
        charArr[0] = char.ToUpper(charArr[0]);
        for(int i = 1; i < charArr.Length; i++)
        {
            if(charArr[i - 1] == ' ')
            {
                charArr[i] = char.ToUpper(charArr[i]);
            }
        }
        string answer = string.Join(string.Empty, charArr);
        return answer;
    }
}
  • 문자열을 모두 소문자로 변경한뒤 Char 배열로 변환한다.
  • 첫번째 Char값의 경우, 반복문에서 따로 체크를 안하기때문에 반복문 전에 첫번째 Char값을 대문자 변환을 시도한다. (어차피 숫자는 ToUpper(), ToLower()로 값이 변경되지 않으므로 굳이 조건문을 추가하지 않는다.)
  • 나머지 값들에 대해 반복문을 돌리면서 단어 앞에 공백이 있으면 해당 i번째 Char 값을 대문자로 변경한다.

 

 

 

기타

- string.Join() : 배열을 string으로 묶는 기능

 

String.Join 메서드 (System)

각 요소 또는 멤버 사이에 지정된 구분 기호를 사용하여 지정된 배열 요소나 컬렉션 멤버를 연결합니다.

learn.microsoft.com

 

 

 

 

 

 

반응형

'Stack > Coding test' 카테고리의 다른 글

[C# / Lv2] 이진 변환 반복하기  (0) 2022.10.07
[C# / Lv2] 최솟값 만들기  (0) 2022.10.07
[C# / Lv2] 최댓값과 최솟값  (0) 2022.10.07
[C++ / Lv2] 더 맵게  (0) 2022.03.03
[C# / Lv2] 주식 가격  (0) 2022.02.26
반응형

 

 

 

 

풀이코드

using System;

public class Solution {
    public string solution(string s) {
        int[] intArr = Array.ConvertAll(s.Split(" "), item => int.Parse(item));
        Array.Sort(intArr);
        string answer = $"{intArr[0]} {intArr[intArr.Length - 1]}";
        return answer;
    }
}
  • 문자열 안의 숫자들이 공백을 기준으로 나뉘어져 있으므로 Split으로 나눠준 뒤, int로 파싱한다.
  • 그렇게 만들어진 배열을 정렬한 뒤, 첫번째 값과 마지막 값을 출력해주면 끝

 

 

 

 

 

반응형

'Stack > Coding test' 카테고리의 다른 글

[C# / Lv2] 최솟값 만들기  (0) 2022.10.07
[C# / Lv2] JadenCase 문자열 만들기  (0) 2022.10.07
[C++ / Lv2] 더 맵게  (0) 2022.03.03
[C# / Lv2] 주식 가격  (0) 2022.02.26
[C++ / Lv 2] 다리를 지나는 트럭  (0) 2022.02.26
반응형

 

 

 

 

이전에 C로 퀵정렬을 구현한 글을 썼었는데, 육안으로 과정이 보이는 글이 아닌 코드만 작성되어있는 글이어서 유니티 C#으로 퀵 정렬 과정을 육안으로 확인할 수 있도록 제작해봤다.

만들면서 파티션 정렬하는 과정에서 high index가 파티션 배열의 범위를 벗어나는 버그가 있었는데, 단순히 조건문 순서상의 오류라 바로 수정했다. (생각보다 그 글이 조회수가 좀 됐는데, 글을 보신 분들이 문제 제기를 안했다는게 의아함)

 

 

 

 

1. 유니티 C# 퀵정렬 프로젝트

- 코드가 아닌 유니티 프로젝트로 올립니다. (깃허브)

 

GitHub - realnity09/QuickSort_CS

Contribute to realnity09/QuickSort_CS development by creating an account on GitHub.

github.com

 

 

 

 

2. QuickSort 컴포넌트 설명

- TargetArrSize : 배열의 길이를 지정할 수 있다.

- Min, Max : 배열 요소의 최소값과 최대값. (지정한 범위 안에서 랜덤 함수로 지정된다.)

- Delay : 정렬하는 속도 (값이 높을수록 느려집니다. WaitForSeconds값.)

※ Scene에 버튼 2개가 붙어있는데, Create arr 버튼으로 배열을 생성하고, Quick sort 버튼을 누르면 정렬이 시작되며 정렬 과정을 눈으로 확인할 수 있습니다.

low index - Red, high index - Blue, pivot index - cyan

※ 정렬이 완료되면 UI element가 초록색으로 변합니다.

 

 

 

3. 퀵정렬 설명

 

퀵정렬(Quick Sort) 구현

퀵정렬(Quick Sort) - 찰스 앤터니 리처드 호어가 개발한 알고리즘이다. - 평균 O(n log n)으로 매우 빠른 정렬속도를 자랑한다. - 기준(Pivot) 값을 기준으로 나머지 원소에 대해 대소관계를 비교하여 큰

srdeveloper.tistory.com

 

 

 

 

 

 

반응형

'Stack > Algorithm' 카테고리의 다른 글

문자열, 숫자 뒤집기  (0) 2021.10.16
퀵정렬(Quick Sort) 구현  (0) 2021.09.19
삽입정렬(Insertion Sort) 구현  (0) 2021.09.18
선택정렬(Selection Sort) 구현  (0) 2021.09.15
버블정렬(Bubble Sort) 구현  (0) 2021.09.14
반응형

 

 

 

 

1. 힙(Heap)

- 최대값 혹은 최소값을 빠르게 찾아낼 수 있도록 고안된 완전이진트리 자료구조이다.

- 부모노드와 자식노드의 키 값 사이에 대소관계가 성립해야하는 조건을 만족해야한다.

- 부모노드의 키 값이 자식노드의 키 값보다 큰 힙을 '최대 힙', 반대를 '최소 힙'이라 부른다.

- 힙의 시간복잡도는 log n이다.

- 위키 (힙 트리)

 

 

 

 

2. 코드

※ A-star pathfind에서 OpenList의 최소 F cost를 가진 노드를 가져오기 위해 적용한 Heap tree 코드이다.

※ 유튜브 영상에 있는 소스를 수정하여 사용했는데, 기존 코드는 배열을 사용하여 맵 사이즈만큼 할당하여 힙을 사용하고 있었다.

※ 그 결과, 실제로 맵 사이즈만큼의 할당이 필요없는데도 불구하고 많은 할당이 일어나 가비지가 많이 발생되므로 List로 변경하고 Capacity를 지정해줌. (만약의 경우 추가 할당이 필요한 경우가 있을 수 있으므로 List로 구성했다.)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IHeapItem<T> : IComparable<T>
{
    int HeapIndex { get; set; }
}

public class HeapList<T> where T : class, IHeapItem<T>
{
    private List<T> m_items;
    public int Count => m_items.Count;
    public int Capacity => m_items.Capacity;

    public HeapList(int maxCapacity = 256)
    {
        m_items = new List<T>(maxCapacity);
    }

    public void Add(T item)
    {
        item.HeapIndex = m_items.Count;
        m_items.Add(item);
        SortUp(m_items[m_items.Count - 1]);
    }

    public void UpdateItem(T item)
    {
        SortUp(item);
    }

    private void SortUp(T item)
    {
        while(true)
        {
            int parentIndex = (item.HeapIndex - 1) / 2;
            T parentItem = m_items[parentIndex];

            if(item.CompareTo(parentItem) > 0)
            {
                Swap(item, parentItem);
            }
            else
            {
                break;
            }
        }
    }

    private void Swap(T itemA, T itemB)
    {
        m_items[itemA.HeapIndex] = itemB;
        m_items[itemB.HeapIndex] = itemA;

        int swapIndex = itemA.HeapIndex;
        itemA.HeapIndex = itemB.HeapIndex;
        itemB.HeapIndex = swapIndex;
    }

    public T GetRoot()
    {
        T rootItem = m_items[0];
        //List의 원소가 1개일 때 List.Count로 원소를 가져오면 에러가 발생하므로 index값을 저장한다.
        int lastIndex = m_items.Count - 1;

        m_items[0] = m_items[lastIndex];
        m_items[0].HeapIndex = 0;
        m_items.RemoveAt(lastIndex);

        SortDown(lastIndex);

        return rootItem;
    }

    private void SortDown(int lastIndex)
    {
        int currentIndex = 0;
        while(true)
        {
            int childLeft = currentIndex * 2 + 1;
            int childRight = currentIndex * 2 + 2;
            int swapIndex = currentIndex;

            //왼쪽 자식 노드 유무 확인
            if(childLeft < lastIndex)
            {
                swapIndex = childLeft;
                //오른쪽 자식 노드 유무 확인
                if(childRight < lastIndex)
                {
                    //양쪽 자식 노드가 존재하면 두 자식 노드의 값을 비교해서 swapIndex 결정
                    //FCost 비교해서 오른쪽 자식노드가 작으면 swapIndex를 childRight로 변경해준다.
                    if(m_items[childLeft].CompareTo(m_items[childRight]) < 0)
                    {
                        swapIndex = childRight;
                    }
                }

                //현재 노드와 자식노드의 값을 비교해서 Swap
                if(m_items[currentIndex].CompareTo(m_items[swapIndex]) < 0)
                {
                    Swap(m_items[currentIndex], m_items[swapIndex]);
                    currentIndex = swapIndex;
                }
                else
                {
                    return;
                }
            }
            else
            {
                return;
            }
        }
    }

    public bool Contains(T item)
    {
        return item.HeapIndex >= m_items.Count ? false : Equals(m_items[item.HeapIndex], item);
    }
}
  • GetRoot()로 루트노드를 힙에서 빼면 말단노드를 Root로 이동 후, 정렬(Sort down)한다.
  • 노드를 추가하면, 말단노드에 추가한 뒤 정렬(Sort up)해서 노드의 위치를 지정해준다.

 

2-1) 힙을 사용하는 노드의 코드 (CompareTo() 구현)

public class Node : IHeapItem<Node>
{
    private int m_hCost;
    private int m_gCost;
    private int m_heapIndex;
    public int HeapIndex { get => m_heapIndex; set => m_heapIndex = value; }
    public int FCost => m_hCost + m_gCost;

    //Heap tree용 compare구현
    public int CompareTo(Node other)
    {
        int compare = FCost.CompareTo(other.FCost);
        if (compare == 0)
        {
            compare = m_hCost.CompareTo(other.m_hCost);
        }

        //힙에서 작은수가 루트로 올라가야하므로 -를 붙여서 반환한다.
        return -compare;
    }
}

 

 

 

 

※ 참고 유튜브 (맵 사이즈 만큼 배열을 할당하는 힙)

https://youtu.be/3Dw5d7PlcTM

 

 

 

 

 

 

반응형

'Stack > Data struct' 카테고리의 다른 글

C AVL 트리(AVL Tree) 구현  (2) 2021.09.11
C AVL 트리(AVL Tree) 설명  (0) 2021.09.10
C 트리 순회(Tree traversal) 구현  (0) 2021.09.10
C 이진탐색트리(Binary search tree) 구현  (0) 2021.09.09
C 트리(Tree) 설명  (0) 2021.09.09
반응형

 

 

 

 

유니티 엔진의 Input 클래스에는 touch라는 구조체가 존재한다. 이 touch라는 구조체의 정보를 바탕으로 모바일 환경에서의 제스처기능을 적용해 카메라를 이동하거나 줌 인/아웃 기능을 구현할 수 있다.

 

 

카메라 이동

using UnityEngine

enum GESTURE
{
    MOVE = 1,
    ZOOM,
}

private void MoveCam()
{
    if (Input.touchCount == (int)GESTURE.MOVE)
    {
        Touch touch = Input.touches[0];
        Camera.main.transform.position = new Vector3(
            Camera.main.transform.position.x - touch.deltaPosition.x,
            Camera.main.transform.position.y - touch.deltaPosition.y,
            Camera.main.transform.position.z);
    }
}
  • Touch 구조체에는 deltaPosition이 존재하는데 이전 프레임과 현재 프레임 사이의 움직인 벡터 값을 받을 수 있다.
  • 이 벡터 값을 이용해서 카메라의 위치를 변경해주면 된다.
  • deltaPosition을 바로 적용해주면 카메라가 엄청 빠르게 움직이니 해당 값에 speed(float) 값을 곱해서 적용해준다.
  • 간단하게 보여주기 위해 작성된 코드로, Camera.main의 카메라 클래스는 캐싱해서 사용하는게 최적화에 도움이 된다.

 

 

 

카메라 줌 인/아웃

private void ZoomCam()
{
    if (Input.touchCount == (int)TOUCH.ZOOM)
    {
        Touch touch_1 = Input.touches[0];
        Touch touch_2 = Input.touches[1];

        //이전 프레임의 터치 좌표를 구한다.
        Vector2 t1PrevPos = touch_1.position - touch_1.deltaPosition;
        Vector2 t2PrevPos = touch_2.position - touch_2.deltaPosition;

        //이전 프레임과 현재 프레임 움직임 크기를 구함.
        float prevDeltaMag = (t1PrevPos - t2PrevPos).magnitude;
        float deltaMag = (touch_1.position - touch_2.position).magnitude;

        //두 크기값의 차를 구해 줌 인/아웃의 크기값을 구한다.
        float deltaMagDiff = prevDeltaMag - deltaMag;

        Camera.main.orthographicSize += deltaMagDiff;
        Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize, 7, 30);
    }
}
  • 줌 기능은 카메라 이동 코드와는 다르게 조금 복잡한데, 결론적으로 이전 프레임과 현제 프레임의 두 터치 사이의 벡터 크기(Maginitude) 값을 이용해서 deltaMagnitude 값을 구한다.
  • 이렇게 구해진 deltaMagnitude 값을 Camera의 orthographicSize에 더해주면 줌 인/아웃 기능 구현이 가능하다.
  • orthographicSize가 너무 작아져서 음수로 내려가면 화면이 뒤집어져 보이므로 Mathf.Clamp로 적절하게 최소, 최대값을 고정해준다.
  • deltaMagnitude 값을 바로 적용하면 줌이 빠르게 적용되니 해당 값에 speed(float) 값을 곱해서 사용해준다.

 

 

 

결과

 

 

 

 

 

 

반응형

+ Recent posts