코틀린-안드로이드

49일차)알고리즘 문제, 숙련 1주차 강의(프레그먼트)

songyooho 2024. 7. 11. 21:16

>알고리즘 문제

1.문제

문제 설명

비내림차순으로 정렬된 수열이 주어질 때, 다음 조건을 만족하는 부분 수열을 찾으려고 합니다.

  • 기존 수열에서 임의의 두 인덱스의 원소와 그 사이의 원소를 모두 포함하는 부분 수열이어야 합니다.
  • 부분 수열의 합은 k입니다.
  • 합이 k인 부분 수열이 여러 개인 경우 길이가 짧은 수열을 찾습니다.
  • 길이가 짧은 수열이 여러 개인 경우 앞쪽(시작 인덱스가 작은)에 나오는 수열을 찾습니다.

수열을 나타내는 정수 배열 sequence와 부분 수열의 합을 나타내는 정수 k가 매개변수로 주어질 때, 위 조건을 만족하는 부분 수열의 시작 인덱스와 마지막 인덱스를 배열에 담아 return 하는 solution 함수를 완성해주세요. 이때 수열의 인덱스는 0부터 시작합니다.


제한사항
  • 5 ≤ sequence의 길이 ≤ 1,000,000
    • 1 ≤ sequence의 원소 ≤ 1,000
    • sequence는 비내림차순으로 정렬되어 있습니다.
  • 5 ≤ k ≤ 1,000,000,000
    • k는 항상 sequence의 부분 수열로 만들 수 있는 값입니다.

2. 솔루션

class Solution {
    fun solution(sequence: IntArray, k: Int): IntArray {
        var answer: IntArray = intArrayOf()
        var end=sequence.size-1
        var start=sequence.size-1
        var sum=sequence[end]
        while(true){
            while(sum<k){
                sum+=sequence[--start]
            }
            if(sum==k) break
            sum-=sequence[end--]  
        }
        while(start>=1&&end>=1&&sequence[end-1]==sequence[end]&&sequence[start-1]==sequence[start]&&sequence[end-1]==sequence[start-1]){
            start--
            end--
        }
        answer+=start
        answer+=end
        return answer
    }
}

 

 

 

 

>숙련 1주차 강의

 

1. 프래그먼트

(1)프래그먼트란

-액티비티 위에서 동작하는 모듈화된 사용자 인터페이스: 액티비티와 분리되어 독립적으로는 동작 불가

-여러 프래그먼트를 하나의 액티비티에 조합하여 창이 여러개인 UI구축 가능 

-한 프래그먼트를 여러 액티비티에서 재사용 가능

 

(2)프래그먼트와 액티비티

<1>액티비티: 인텐트로 액티비티간 데이터 전달

<2>프래그먼트: 액티비티의 프래그먼트 매니저에서 메소드로 프래그먼트간 데이터 전달

 

(3)프래그먼트 생명주기

<1>onAttach()

-프래그먼트가 액티비티에 연결될 때 호출

-아직 프래그먼트가 액티비티에 완전히 연결되진 않은 상태

<2>onCreate()

-프래그먼트 생성시 호출

-초기화, 리소스 바인딩등을 수행가능

<3>onCreateView()

-프래그먼트의 레이아웃을 인플레이트

-뷰 생성 및 레이아웃 설정

<4>onViewCreated()

-onCreateView()에서 반환된 View객체가 이 함수에 파라미터로 전달됨

-초기화: View의 초기값을 설정하거나 adapter를 초기화 수행을 이곳에서 함.

<5>onViewStateRestored()

- onViewStateRestored() 함수는 저장해둔 모든 state 값이 Fragment의 View 계층구조에 복원됐을 때 호출된다.

<6>onStart()

-프래그먼트가 사용자에게 보여질 준비완료시 호출

-필요한 리소스 할당 및 애니메이션 시작 가능

<7>onResume()

-프래그먼트가 사용자와 상호작용 가능 상태일때 호출

-프래그먼트가 포그라운드에 있을때 실행되는 작업을 여기서 처리

<8>onPause()

-프래그먼트 일시정지시 호출

-상태저장, 스레드 중지

<9>onStop()

-프래그먼트가 사용자에게 보이지 않을때 호출

-리소스 해제, 스레드 정지

<10>onDestroyView()

-프래그먼트의 뷰와 관련 리소스 정리시 호출

<11>onDestroy()

-프래그먼트 파괴시 호출

-프래그먼트 상태 정리 및 리소스 해제

<12>onDetach()

-프래그먼트를 액티비티로부터 분리시 호출

-액티비티와의 모든 연결 해제

이전버전(onActivityCreated())만 제외하고 보기

 

 

-onPause()에 들어가는 경우: 부모액티비티나 다른 프래그먼트로 대체되는 경우 onPause로 넘어가고 이후 onDestroyView()까지 진행되면서 기존의 뷰는 전부 해제됨

=>이후 다시 돌아오면 뷰에 변경사항은 전부 초기화되고 초기 화면이 띄워짐

 

@프래그먼트에서 뷰바인딩 하는 방법(메모리 누수를 막기위함)

-fragment의 뷰는 onDestroyView에서 사라지지만 fragment는 onDestroy가 호출되어야 사라진다.

-즉, binding을 생성하면 없애주지 않는 이상 사라지지않고 메모리 누수를 일으킨다.

-예시: 한 레이아웃에 프레그먼트를 바꾸면서 보여줄 경우 onDestroyView()까지만 가기때문에 한번 생성된 프레그먼트는 사라지지 않는다.

private var binding:FragmentFirstBinding? =null

private val binding get() = _binding!!
	
    .
    .
    .

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentFirstBinding.inflate(inflater, container, false)
        return binding.root
    }
    
    override fun onDestroyView(){
    	super.onDestroyView()
        _binding = null
    }

{1} binding과 _binding을 두 개 쓰는 이유: 

-onDestroyView()에서 null로 값을 바꾸기 위해서는 타입을 nullable로 만들어줘야 하는데 이 경우 binding을 쓸때마다 널처리를 해줘야한다.

-그러나 _binding에 !!처리를 해줘서 get()으로 binding에 할당하면 쓸 때 마다 널처리를 해야하는 귀찮음을 없앨 수 있다. 

{2}값을 대입 삭제하는것은 _binding에서 하고 사용하는것은 binding에서 함.

 

 

(4)프래그먼트 사용하는 이유

-Activity보단 fragment로 일부만 바꾸는 것이 자원 사용량이 적음

-재사용 가능한 레이아웃을 분리해 관리 가능

-한 Activity에서 여러 화면 보여줄 수 있음

 

(5)프래그먼트 사용법

<1>xml레이아웃 생성

<2>프래그먼트 클래스 정의

class SecondFragment : Fragment() {

    private var _binding: FragmentSecondBinding?=null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding=FragmentSecondBinding.inflate(inflater,container,false)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding=null
    }
}

 

<3>gradle에서 dependencies에서 추가

implementation("androidx.fragment:fragment-ktx:1.8.1")

 

<4> 코드에서 동적으로 프래그먼트 추가

private fun setFragment(frag:Fragment){
    supportFragmentManager.commit{
        replace(binding.frameLayout.id,frag)
        setReorderingAllowed(true)
        addToBackStack("")
    }
}

-replace(id,fragment): 해당 id의 레이아웃에 fragment를 바꿔 넣음

-setReorderingAllowed(true): 여러 transaction사용시 불필요한 프레그먼트를 실행시키지 않거나 나중에도 필요한 프래그먼트를 완전히 제거하지(onDetach())하지 않는것. 

@예시

[1] A 프레그먼트를 추가하고 (add) B프레그먼트를 추가한다하자(add)

[2]원래라면 A가 onAttach() ~ onReumse()이 우선 뜨고

[3]이후 A는 onPause() ~ onDestroyView()가 뜨고 B가 추가되며 B는 onAttach() ~ onResume()콜백 함수가 실행된다.

=> setReorderingAllowed(true)를 쓰면 불필요하게 A가 생성되지 않고 B만 생성됨

 

-addToBackStack(String?): FragmentManager상의 백스택에 transaction(commit으로 묶인 단위)을 채워넣는다. 

=>뒤로가기 누를 시 이전 프래그먼트가 나오게 된다.

=>최종적으로 모든 프레그먼트가 없는 상태까지 감.

=>String? 부분은 백스택에 들어갈때 transaction의 이름. 필요없으면 null을 넣어도 된다.

@popBackStack(): 뒤로가기를 누를 때 처럼 백스택에서 transaction을 하나씩 빼냄

supportFragmentManager.popBackStack()

=>String값을 넣어 특정 transaction위의 스택을 전부 비울 수 있다.

fragmentManager.popBackStack("hello2", FragmentManager.POP_BACK_STACK_INCLUSIVE)

 

@백스택에서 생명주기 상태: onPause()상태로 유지된다.

 

@childFragmentManager&parentFragmentManager

[1]사용: 프래그먼트 내에서 사용하는 것으로 외부 프래그먼트매니저를 참조하게 해준다.

[2]종류

- childFragmentManager:프래그먼트 내부의 자체적인 프래그먼트매니저

=>프래그먼트 내에 프래그먼트를 넣는 경우 이것을 사용한다.

- parentFragmentManager:상위 프래그먼트 혹은 액티비티의 프래그먼트 매니저

=>프래그먼트에서 상위에 존재하는 프래그먼트나 액티비티의 프래그먼트 매니저를 사용할 시 이것을 사용

 

@ setPrimaryNavigationFragment(true)

[1]프래그먼트 내부에 프래그먼트가 있는 경우 해당 프래그먼트부터 지워줌

=>즉, childFragmentManager의 백스택에 있는 프래그먼트부터 지워준다.

[2]설정을 안 한 경우: 프래그먼트가 지워지면서 안에 있는 child의 백스택은 한번에 통으로 날아감

 

<5>Transaction

[1]commit으로 묶이는 작업단위를 transaction이라 한다.

[2]작업 종류

-add(containerId, Fragment, tag:String) : 프래그먼트를 추가한다.

-remove(fragment): 프래그먼트를 제거 한다.

supportFragmentManager.getFragmentByTag(태그명:String)

=>기존에 추가되어 있는 프래그먼트를 태그를 이용해서 참조를 가져온다. 

 

-detach&attach

{1}detach(Fragment): 프래그먼트를 떼어내는데 완전히 프래그먼트를 없애는게 아닌 onDestroyView()까지만 간다.

=>즉 보이지는 않지만 container에는 남아있는것

{2}attach(Fragment): detach한 프래그먼트를 onCreateView부터 다시 시작시켜 사용자에게 보이게 한다.

 

-show(Fragment)&hide(Fragment)

{1}그저 보이거나 안보이게만 해준다.

{2}어떠한 생명주기도 타지 않는다.