n명에게 각각 예상 등수값을 입력받고, 그 값들을 토대로 불만족 지수가 최소로 나오도록 구성하여 불만족 지수의 최소값을 출력
불만족 지수란 예상 등수가 1등이고, 실제 순위 구성 후 등수가 3등인 경우 (|1-3|)으로 2의 값이 됨
(n의 범위는 1이상 500,000이하)
풀이법 구상
예상 순위보다 실제 순위가 높든 낮든 무관하게 그 차이값만큼이 불만족 수치가 됨
최대한 예상 순위가 실제 순위가 되도록 해야하므로 정렬 후 각 예상 순위값을 돌며 실제 순위와의 차이값을 구해야함
정렬 + 반복문이 필요함
-> 스위프트 기본 정렬 메소드의 시간복잡도 - O(n log n)
-> 반복문 시간 복잡도 - O(N)
-> 동시에 일어나지 않고 정렬 후 반복문 돌게됨
코드구현 (스위프트사용)
import Foundation
funcsolution(_arr: [Int]) -> Void {
var sum =0let temp = arr.sorted()
for i in1...arr.count { sum +=abs(i - temp[i-1]) }
print(sum)
}
var arr: [Int] = []
let cnt =Int(readLine()!)!for_in0..<cnt { arr.append(Int(readLine()!)!) }
solution(arr)
lazyvar leftTitleLabel1 = getLabelView(titleStr: "서울특별시", fontSize: 20.0, fontWeight: .bold, fontColor: .white)
lazyvar leftTitleLabel2 = getLabelView(titleStr: "9°", fontSize: 40.0, fontWeight: .medium, fontColor: .white)
lazyvar leftStackView =UIStackView().then {
$0.backgroundColor = .green
// 스택 요소로 포함할 subView들을 선언let stackView =UIStackView(arrangedSubviews: [leftTitleLabel1, leftTitleLabel2])
$0.axis = .vertical // 수직 방향으로 스택을 구성$0.distribution = .fill // 요소들이 스택을 채울 수 있게 분포되도록 구성$0.alignment = .leading // 왼쪽 끝에 붙어서 요소가 나열되도록 구성$0.spacing =0// 요소 간의 간격 0
}
// helper methods - 컨테이너 뷰를 가진 UILabel 컴포넌트를 반환funcgetLabelView(titleStr: String, fontSize: Double, fontWeight: UIFont.Weight, fontColor: UIColor) -> UIView {
let titleLabel =UILabel().then {
$0.text = titleStr
$0.font = .systemFont(ofSize: fontSize, weight: fontWeight)
$0.textColor = fontColor
}
let containerView =UIView().then {
$0.backgroundColor = .systemPink
$0.backgroundColor = .clear
}
containerView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.top.bottom.leading.trailing.equalToSuperview()
}
return containerView
}
2-3. 우측 상단의 구름 이미지, 날씨, 최고/최저 기온을 포함한 수직 UIStackView
let cloudImgView =UIImageView(image: UIImage(systemName: "cloud.fill")).then {
$0.tintColor = .white
}
// getLabelView는 상단 helper method 참조lazyvar rightTitleLabel1 = getLabelView(titleStr: "대체로 흐림", fontSize: 18.0, fontWeight: .medium, fontColor: .white)
lazyvar rightTitleLabel2 = getLabelView(titleStr: "최고: 21° 최저 7°", fontSize: 18.0, fontWeight: .medium, fontColor: .white)
lazyvar rightStackView =UIStackView().then {
$0.backgroundColor = .blue
let stackView =UIStackView(arrangedSubviews: [cloudImgView, rightTitleLabel1, rightTitleLabel2])
$0.axis = .vertical
$0.distribution = .fill
$0.alignment = .trailing // 요소들이 오른쪽 끝에 붙어 나열될 수 있도록 구성$0.spacing =3
}
좌우측 상단에 스택뷰를 추가한 후
2-4. - 하단의 각 시간대별 날씨를 포함한 수평 UIStackView
let weatherWithTimeList = [
["오전 8시", "10°"],
["오전 9시", "12°"],
["오전 10시", "15°"],
["오전 11시", "17°"],
["오후 12시", "19°"],
["오후 1시", "20°"],
]
lazyvar weatherViews: [UIView] = []
// helper method - 시간 및 기온 정보 배열을 토대로 하단 수평 스택뷰의 요소로 쓰이는 UIView 반환// viewDidLoad 내에서 호출하여 weatherViews 배열 구성funcconfigureWeatherOfTime() {
weatherWithTimeList.map { info in
weatherViews.append(getWeatherViewOfTime(timeStr: info[0], temper: info[1]))
}
}
lazyvar bottomStackView =UIStackView().then {
let stackView =UIStackView(arrangedSubviews: weatherViews)
$0.axis = .horizontal // 수평 방향으로 요소가 나열되도록 지정$0.distribution = .fillEqually // 모든 요소가 스택 내에서 동등한 크기를 가지도록 지정$0.alignment = .leading
$0.spacing =5
}
하단 스택뷰를 추가한 후
3. 레이아웃 구성
privatefuncsetLayouts() {
// add viewsself.view.addSubview(backView)
// 전체 컨테이너 뷰에 좌측 상단, 우측 상단, 하단 스택뷰를 추가
backView.addSubview(leftStackView)
backView.addSubview(rightStackView)
backView.addSubview(bottomStackView)
// add views in StackView// 좌측 상단 스택뷰 내에 요소로 사용될 sub view들을 추가
leftStackView.addArrangedSubview(leftTitleLabel1)
leftStackView.addArrangedSubview(leftTitleLabel2)
// 우측 상단 스택뷰 내에 요소로 사용될 sub view들을 추가
rightStackView.addArrangedSubview(cloudImgView)
rightStackView.addArrangedSubview(rightTitleLabel1)
rightStackView.addArrangedSubview(rightTitleLabel2)
// 하단 스택뷰 내에 요소로 사용될 sub view들을 추가
weatherViews.map { view in
bottomStackView.addArrangedSubview(view)
}
// set constraints
backView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(130)
make.leading.equalToSuperview().offset(20)
make.trailing.equalToSuperview().inset(20)
}
leftStackView.snp.makeConstraints { make in
make.leading.top.equalToSuperview().offset(15)
}
cloudImgView.snp.makeConstraints { make in
make.top.equalToSuperview()
}
rightStackView.snp.makeConstraints { make in
make.top.trailing.equalToSuperview().inset(15)
make.bottom.equalTo(leftStackView.snp.bottom)
}
bottomStackView.snp.makeConstraints { make in
make.top.equalTo(leftStackView.snp.bottom).offset(30)
make.leading.trailing.equalToSuperview().inset(10)
make.bottom.equalToSuperview().inset(15)
}
}
4. 추가) 수직 스택뷰 요소 간 spacing 달리 주기
// 구름 이미지 UIImageView를 감싸는 컨테이너 뷰 정의let cloudImgContainerView =UIView().then {
$0.backgroundColor = .clear
}
let cloudImgView =UIImageView(image: UIImage(systemName: "cloud.fill")).then {
$0.tintColor = .white
$0.contentMode = .scaleAspectFill
}
// 레이아웃 구성 변경
cloudImgView.snp.makeConstraints { make in
make.top.bottom.leading.trailing.equalToSuperview()
}
// 구름 이미지 컴포넌트 하단 요소에 대해 top 방향으로 원하는 만큼의 여백값을 추가
rightTitleLabel1.snp.makeConstraints { make in
make.top.equalTo(cloudImgView.snp.bottom).offset(20)
}
날짜 라벨은 날짜 딱 한 줄만 보여주도록, 내용 라벨은 여러줄에 걸쳐 보여줄 수 있도록 제약조건 설정을 해주었다 (각각 모두 12로 맞춰줌)
이 때 hugging priority 관련의 제약조건 오류가 생기는데, Content Hugging Priority가 두 라벨 모두 같은 값이고, 셀 내의 제약조건에 따라 요소들을 위치시키려고 하자니, 어떤 요소를 더 늘려서 맞춰넣어야 하는지 애매해져버려 발생하는 오류인 것 같다
Content Hugging Priority값이 더 낮으면, 그 값이 더 높은 요소 대신에 크기가 늘려져서 제약조건에 맞도록 설정된다
값이 더 높은 요소는 정해진 조건값에 따라 그 크기를 유지할 수 있게 된다
내용 라벨의 Content Hugging Priority 값을 1 낮추어서, 날짜 라벨의 그 값보다 더 낮도록 설정해주면 아래와 같이 오류가 해결된다
content compression resistance priority는 요소가 가지는 크기가 커지는 경우에 대해, 찌그러질 것이냐 말것이냐에 대한 우선순위를 정하는 것이다
이미지에서의 컬렉션뷰 셀과 같이 정해진 범위내에서 만약 내용 라벨에 담길 컨텐츠가 많아지면, 내용 라벨이 자신의 크기를 줄이던지, 혹은 날짜 라벨이 줄어들던지 해야할 것이다
이 경우에 대해, content compression resistance priority값이 날짜 라벨이 더 높게 설정된다면 날짜 라벨은 크기를 유지하고, 값이 더 낮은 내용 라벨이 찌그러지게(크기가 줄어들게) 되는 것이다
일단 내가 이해한 바로는,,,
Content Hugging Priority
-> 자리 남는다; 누가 몸집 더 키울래? (값 높은 애 : 전 아닙니다 / 값 낮은 애 : 아휴 제가 늘릴게요;)
Content Compression Resistance Priority -> 뭐야 자리 부족하잖아; 누가 찌그러질래? (값 높은 애 : 전 아니라고요 / 값 낮은 애 : 예예 저요)