02/07 본캠프 #32

guno park·2024년 2월 7일
0

본캠프

목록 보기
32/77

알고리즘 풀어보기

H-index


H-index 설명

풀이

using System;
using System.Linq;

public class Solution {
    public int solution(int[] citations) {
        int answer = 0;        
        int count =0;
        int num=0;
        citations = citations.OrderBy(x=>x).ToArray(); //정렬
        for (int i =0;i<citations.Length;i++){ 
            count = citations.Count(x => x >= citations[i]); //조건에 맞는 것만 체크
            num=count >= citations[i] ? citations[i] : count; //두 수 중 작은 것을 사용
            if (num >= answer)               //가장 큰 값을 사용한다.
                    answer = num;
        }                 
        return answer;
    }
}

n^2 배열 자르기

첫번째 시도 (메모리 터짐)

2차원 배열을 모두 작성해서 해당하는 값을 구해보려고 했으나, 어레이가 메모리가 감당할 수 있는 크기를 넘어감.
ex) 10000000, 99999999999, 99999999999

두번째 시도 (시간초과)

using System;
using System.Collections.Generic;

public class Solution {
    public int[] solution(int n, long left, long right) {
      int[] answer = new int[]{};  
        long count = 0;
        List<int> answer1 = new List<int>();
        int num = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                num= i >= j ? i + 1 : j + 1;
                
                if (count >= left && count<=right)
                {
                    answer1.Add(num);
                }
                else if (count > right)
                    break;
                count++;
            }
        }     
        
        return answer=answer1.ToArray();
    }
}

방법1. 리스트 -> 어레이 변환 제거해보기.
여전히 시간초과

방법2. 필요한 부분만 만들기

using System;
using System.Collections.Generic;

public class Solution {
    public int[] solution(int n, long left, long right) {
      int[] answer = new int[right-left+1];  
        long count = 0;
        List<int> answer1 = new List<int>();
        int num = 0;
        for (int i = (int)left/n; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                num= i >= j ? i + 1 : j + 1;
                
                if (i*n+j >= left && i*n+j<=right)
                {
                    answer1.Add(num);
                }
                else if (i*n+j > right)
                    break;
                count++;
            }            
        }     
        
        return answer = answer1.ToArray();
    }
}

시간 초과가 났는데 문제를 찾았다.
문제 원인
int 자료형을 넘어가게 되어서 무한반복 되었던 것이다.
for문의 자료형을 long으로 바꿔주고 해결되었다.

과제해설강의 정리

Render Mode

Overlay - 게임 씬에서 정한 게임 화면위에 덮어씌워짐
Camera - 카메라가 여러개 있을 때 카메라를 지정해 거기에만 띄우겠다.
World Space - 게임 화면이 아닌 월드 스페이스에 좌표로 띄움

anchor와 Pivot

Rect transform에서 가장 중요한 것 두 가지

앵커가 바뀜에 따라 좌표가 바뀜. 부모에 대한 나의 위치
해상도(부모의 크기가 변하면) 좌표도 변하는데 앵커를 사용하면 해상도가 변해도 위치를 고정할 수 있다.

자식 오브젝트가 앵커와 앵커기준 좌표로 책정되기때문에 사용하기 편리하다.
그렇기 때문에 오브젝트들끼리 잘 뭉치는게 좋을 듯 하다.
애매한 위치는 손으로 옮기겟지만 그런게 아니라면 피벗을 사용하면 편하게 만들수있음.

Pivot - 나에 대한 나의 위치 현재 오브젝트의 중심점을 어디로 잡을 것인가.하는 얘기
만약 피벗이 0,0이면 왼쪽 아래, 1,1이면 오른쪽 위를 중심점으로 잡는다. (중요 : 앵커랑 피벗 둘다)

쉬프트 - 피벗만 , 알트 - 포지션만 , 같이 사용 가능
스트레치 - 잡아늘림.

Content Size Fitter

내용 늘어나면 크기가 바뀌는데 그 크기에 맞게 늘어남. 굉장히 유용한 기능인듯

텍스트 컴포넌트에 Best fit 누르면 크기에 맞춰서 폰트 사이즈를 조절해줌.
최소, 최대를 정해서 글자가 늘어나면 그 사이 값으로 변경됨.
근데 Content Size Fitter랑 두 개 중에 편한 걸 쓰도록 하자.

Json

여기서는 Newtonsoft 안쓰고 JsonUtility 사용

public void SaveUserData() //저장
{
string data =JsonUtility.ToJson(User); //문자열로 반환되기때문에
string path = Path.Combine(Application.dataPath, User.Name +".json");
//Combine 앞에 Path와 뒤에 Path를 결합함 이거 쓰면 지난번처럼 다 +처리 안해도됨.
//dataPath는 에셋 폴더 내, 일반적으로는 퍼시스턴스데이터
File.WrtieAllText(path,data);
}
public void LoadUserData(string userName) //불러오기
{
string path = Path.Combine(Application.dataPath, userName+".json");
string data = File.ReadAllText(path);
UserData User = JsonUtility.FromJson<UserData>(data); 
}

저장과 불러오기는 진행/역순 이라고 생각하면 됨. 다만 불러올 때 타입형을 지정해주며 변환해야함.

제이슨에 저장된 값과 실제 변수명이 매칭이 되야 불러올 수 있음. 아니면 null됨.

UIManager

UI매니저에서 관리하는 방법 : 오브젝트 풀링이랑 개념은 비슷함, UI매니저가 모든 팝업들을 가지고 있음.
이 팝업 리스트들을 만들 때 오브젝트로 만들면 박싱/언박싱이 일어나서 퍼포먼스적으로 좋지않다.그래서 UI베이스를 만들고 그것들을 상속시켜 리스트를 만든다.
그리고 만들어진 UI들을 프리팹으로 관리한다.

uimanager.CS
//내가 생성한 UI리스트 또한 들고있어야 파괴할 수 있음.
public void Show(stirng uiName){
UIBase ui = UI_List.Find(obj=> obj.name == uiName);

if (ui==null)
return;

ui.Show();

}
----------------------------------------------------------
UIBase.cs
  
public Canvas canvas;
public void Show(){
Instantiage(gameObject,UIManager.Instance.mainCanvas.transform); //캔버스 하위에 오브젝트 복제
obj.name = obj.name.Replace("(Clone)","") //이름 변경하기

UIManager.Instance.UI_Obj_List.Add(obj.GetComponent<UIBase>();
}
//숨길때는 리스트에서 먼저 지우고 게임오브젝트를 파괴함.

잡다한 내용

오브젝트 그룹화

ATM 기능들끼리 한 오브젝트에 뭉쳐놨는데 나는 그렇게했나?
여기서도 버티컬 레이아웃 그룹을 써서 정렬을 하기 위해 한 오브젝트로 뭉친듯.
맽 밑에 차일드 포스 익스팬드 하면 내가 패딩이나스패이싱 안해줘도 강제로 띄워짐(균일하게 동)

OnClick Event

내가 스크립트를 안짜도 버튼 컴포넌트의 온클릭에 GameObject 들어가면 켜고 끄는게 기본으로 있음.
거기에 체크하는 방식으로도 가능. => 기본적으로 있는 기능들이 있다.

기타

  • 생각하는 중요도에 따라 폴더 앞에 번호를 붙여서 정렬 순서를 정해줄 수있다.

  • 싱글턴 만들 때 대충 만드는데 좀 더 꼼꼼하게 하자

void Awake(){
	if(instance ==null)
	instance = this;
	else
	Destroy(gameObject);
}
  • TMP에는 넘어갔을 떄 어떻게 처리할 것인지에 대해 따로 설정할 수 있는 등 다양하다.
    html 작성 방식도 적용 가능 ex) 볼드체 이런 느낌
    이렇게 하면 볼드와 아닌 것들을 혼용 가능.

제네릭 특강 (제네릭 기초)

개발자가 하는 일
번거로운 짓을 줄이기 위해 번거로운 짓을 한다.
반복되는 데이터 - 변수
로직 - 함수
변수들 - 클래스(상속)

오늘 실습은 제네릭 싱글톤

매니저를 생성할 때 자동으로 모시깽 할수 있도록 상속구조를 만들어봄.
싱글톤 베이스라는 상속구조를 하나 만들어두고, 게임매니저가 싱글톤베이스를 상속받음.

싱글톤으로 구현하는데 클래스 명도 매개변수처럼 내가 지정하고 싶다! 그럴 때 제네릭
제네릭을 사용하려면 제네릭 클래스로 만들어야됨, 그럴려면 클래스 이름 뒤에 붙여줘야됨.
바꾸고 싶은 클래스 이름 있던 자리에 T 만 넣어주면됨 매개변수 쓸때랑 별반 차이 없음.
작성할 때 where T : MonoBehaviour 적용해서 들어갈 수 있는 클래스 제한.

동적 생성

씬에다가 올려두면 그 작업 순서를 보장할 수 없음.
스크립트 익스큐션 오더라고 직접 실행순서를 지정해줄수는 있는데 스크립트를 한두개 짜는게 아니라서 비효율적임.

동적생성(스크립트로 실행)하면 순서대로 실행하기도 편함.

//프로퍼티를 이용
using System;
using UnityEngine;

public class SingletoneBase<T> : MonoBehaviour where T : MonoBehaviour
{
    // 프로퍼티
    private static T _instance; //실제 동작부

    public static T Instance //접근 포트
    {
        get
        {
            if (_instance == null)
            {
                string typeName = typeof(T).FullName; 
                GameObject go = new GameObject(typeName);
                _instance = go.AddComponent<T>();
                
                DontDestroyOnLoad(go);
            }

            return _instance;
        }
    }


    void Awake()
    {
        Init();
    }

    public virtual void Init()
    {
        Debug.Log(transform.name + " is Init");
    }
}

이런 부분을 관리하기위해 GameScene이라는 스크립트만 하나 동작하는거임.(이름은 달라도됨)
여기서는 필요한 시점에 매니저들을 실행시킴. (Debug.Log 같은걸로)

필요할 때 만들어서 쓰면 중복 에러를 방지할 수 있다.

제네릭이란? (제네릭의 시초)

문자 숫자 불리언 매니저 등등 다 오브젝트로 만들어져 있음.
리스트 장점 : 다 때려박을 수 있다.
단점 : 가져올때마다 확인하면서 써야된다.
근데 이렇게 사용하면 값 > 참조 > 값 박싱 언박싱이 자주 일어나서 성능에 큰 영향을 끼친다.

그래서 리스트에 제네릭으로 타입을 제한해서 사용함. (제네릭의 시초)

만약 면접에서 박싱 언박싱을 얘기한다면 박싱 언박싱이 어떤거고 성능적으로 어떤 차이가 있으며 이걸 해결하기위해 제네릭을 사용할 수 있다~!까지 얘기해야됨.

코딩 팁

순환연결리스트

순환연결리스트는 잘 안쓰고 연결리스트의 처음 시작이나 끝점을 자주씀.
반복해야되면 굳이 순환을 쓰는 것보다 while문을 쓰는게 낫다.
while문을 사용한다면 끝나는 시점을 명시해줘야됨.

유니티 버전 이슈

같은 년도, 같은 버전이면 바꿔도 그렇게 큰 차이는 없음.
끝에 소숫점은 큰차이 없고, 앞번호는 미세하게 차이는 있을 수 있지만 크게 못느낀다고함.
연도가 바뀌면 그건 문제가있다.
버전 다르면 안드로이드나 IOS 빌드할 때 달라짐. 그래서 만들 때 LTS 되는 최신버전(한 1년 전꺼) 사용하는게 좋음 완전 최신버전은 불안한 요소가 보이니까 비추천

공격 판정을 어떻게 둘 것인가?

예~전에 배운 방법은 트리거 처리였고, 이번에 배운 방식은 애니메이션 이벤트 처리였다.
이 두 방법의 차이점이라고 할만한 건
충돌이 우선이면 콜라이더 처리 / 모션이 우선이면 애니메이션 이벤트 처리

연출을 어떻게하느냐에따라 방식이 정해진다는 거지, 정답은 없다.

매니징

트러블 이슈를 엑셀시트나 노션에 업로드하고, 서로 진행상황에 대해 피드백하고 기록을 남긴다.
히스토리를 관리 안해주면 이후에 문제가 계속 터진다.

규칙을 정해서 스크립트 작성에만 집중할 수 있게끔 하는 것이 매니징이다.

보통 작업을 분류한다고 하면 깃에서 충돌안나는 범위에서 분류함.
씬을 분리해서 작업하는 경우가 좋음.

0개의 댓글