
* 문제
정수 x가 주어질 때, x가 팰린드롬이면 true를, 아니면 false를 반환하라.
* 예시 1
입력: x = 121
출력: true
설명: 121은 왼쪽→오른쪽, 오른쪽→왼쪽 모두 동일하게 읽힌다.
* 예시 2
입력: x = -121
출력: false
설명: 왼쪽에서 읽으면 -121, 오른쪽에서 읽으면 121- 이므로 팰린드롬이 아니다.
* 예시 3
입력: x = 10
출력: false
설명: 오른쪽에서 읽으면 01이 되므로 팰린드롬이 아니다.
* 제약 사항
- −2³¹ <= x <= 2³¹ - 1
처음에는 문자열로 리스트에 담은 다음에 정방향 리스트와 역방향 리스트를 비교하면 되겠다! 해서 비교를 했다
class Solution {
bool isPalindrome(int x) {
List<String> xList = [];
List<String> reverseList = [];
xList.addAll(x.toString().split(''));
reverseList.addAll(xList.sublist(0, xList.length).reversed);
if (xList == reverseList) {
return true;
} else {
return false;
}
}
}
그런데 같은 값이라도 false가 나와서 무슨 일인가 찾아봤더니 저 상태에서는 리스트 그 자체를 비교하는 거라 false가 나오는 게 맞다. 그래서 그 리스트 안에 있는 걸 비교하려면 join()을 해줘서 합쳐줘야 한다.
class Solution {
bool isPalindrome(int x) {
List<String> xList = [];
List<String> reverseList = [];
xList.addAll(x.toString().split(''));
reverseList.addAll(xList.sublist(0, xList.length).reversed);
if (xList.join() == reverseList.join()) {
return true;
} else {
return false;
}
}
}
join()을 붙여서 제출했더니 성공~
추가 문제로 문자열로 바꾸지 않고 푸는 문제도 있었다
class Solution {
bool isPalindrome(int x) {
if (x < 0) return false;
List<int> ii = [];
while (x > 0) {
int temp = x % 10;
ii.add(temp);
x = x ~/ 10;
}
if (ii.join() == ii.reversed.join()) {
return true;
} else {
return false;
}
}
}
튜터님과 같이 풀어보았다. 먼저 정수 x가 음수인지 양수인지 검사하고 음수면 바로 false를 반환하고 아니라면 아래 코드가 진행된다.
x % 10
→ 가장 마지막 자릿수 추출
ii.add(temp)
→ 그 자릿수를 리스트에 저장
x = x ~/ 10
→ 마지막 자릿수 제거
예: x = 121
1회: 1 → [1]
2회: 2 → [1, 2]
3회: 1 → [1, 2, 1]
마지막 수를 추출하고 제거하는 형식으로 리스트에 저장한 후에 그 리스트와 reversed된 리스트를 비교하여 문제를 풀었다.
* 문제
로마 숫자는 7개의 서로 다른 기호로 표현된다: I, V, X, L, C, D, M.
기호 | 값
I | 1
V | 5
X | 10
L | 50
C | 100
D | 500
M | 1000
예를 들어, 2는 로마 숫자로 II라고 쓴다. 이는 1이 두 번 더해진 것이다.
12는 XII로 쓰며, X + II이다.
27은 XXVII로 쓰며, XX + V + II이다.
로마 숫자는 보통 왼쪽에서 오른쪽으로 큰 값에서 작은 값 순서로 작성된다.
하지만 4는 IIII가 아니다. 대신 IV로 쓴다.
이는 1이 5 앞에 오면 빼는 방식이 적용되어 4가 되기 때문이다.
같은 원리가 9에도 적용되며, 9는 IX로 쓴다.
뺄셈이 사용되는 경우는 총 여섯 가지이다:
I는 V(5)와 X(10) 앞에 올 수 있으며, 각각 4와 9를 만든다.
X는 L(50)과 C(100) 앞에 올 수 있으며, 각각 40과 90을 만든다.
C는 D(500)와 M(1000) 앞에 올 수 있으며, 각각 400과 900을 만든다.
주어진 로마 숫자를 정수로 변환하라.
* 예제 1:
입력: s = "III"
출력: 3
설명: III = 3
* 예제 2:
입력: s = "LVIII"
출력: 58
설명: L = 50, V = 5, III = 3
* 예제 3:
입력: s = "MCMXCIV"
출력: 1994
설명: M = 1000, CM = 900, XC = 90, IV = 4
* 제약 조건:
1 ≤ s.length ≤ 15
s는 문자 ('I', 'V', 'X', 'L', 'C', 'D', 'M')만 포함한다.
s는 [1, 3999] 범위의 유효한 로마 숫자임이 보장된다.
처음에는 어떻게할지 고민이 많았는데 일단 로마 숫자를 Map으로 만들어서 문자와 숫자를 저장하기로 했다. 중간에 조건이 하나가 있어서 numList를 검사하면서 현재 문자가 다음 문자보다 큰 수라면 더하고 현재 문자가 다음 문자보다 작다면 총합에서 빼는 식으로 만들었다. 그리고 numList[i]가 맨 마지막 자리면 그냥 더해주는 방식으로 문제를 풀었다.
class Solution {
int romanToInt(String s) {
Map<String, int> romanNumMap = {
"I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000,
};
List<String> numList = [];
numList.addAll(s.split(''));
int total = 0;
for (var i = 0; i < numList.length; i++) {
if (i != numList.length - 1) {
if (romanNumMap[numList[i]]! >= romanNumMap[numList[i + 1]]!) {
total = total + romanNumMap[numList[i]]!;
} else {
total = total - romanNumMap[numList[i]]!;
}
} else {
total = total + romanNumMap[numList[numList.length - 1]]!;
}
}
return total;
}
}
뭔가 복잡해 보이지만.. 제출은 되어서 마무리 했다.
자식 위젯(child)을 특정 영역으로 잘라내는 위젯
단순히 둥글게 보이게 하는 게 아니라
실제 렌더링 영역을 제한
이미지, 동영상, 애니메이션은
Container decoration만으로는 잘리지 않음
Clip 계열은 child 자체를 자름
Rounded Rectangle(둥근 사각형) 으로 child를 클리핑
가장 많이 쓰이는 Clip 위젯
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: ...
)
borderRadius (필수 개념)
borderRadius: BorderRadius.circular(16)
가능한 형태:
BorderRadius.only(
topLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
)
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://picsum.photos/300',
fit: BoxFit.cover,
),
)
타원(Oval) 으로 child를 클리핑
정사각형 → 원(circle)
ClipOval(
child: ...
)
borderRadius 없음
모양 선택 불가
단순하고 빠름
ClipOval(
child: Image.network(
'https://picsum.photos/300',
width: 120,
height: 120,
fit: BoxFit.cover,
),
)
width == height → 원
다르면 → 타원
Path를 직접 정의해서 클리핑
자유도 높음
ClipPath(
clipper: MyClipper(),
child: ...
)
class MyClipper extends CustomClipper<Path> {
Path getClip(Size size) {
final path = Path();
return path;
}
bool shouldReclip(CustomClipper<Path> oldClipper) {
return false;
}
}
moveTo : 시작점
lineTo : 직선
quadraticBezierTo : 곡선
close : 닫기
다시 클리핑해야 하면 true
모양 고정 → false
값에 따라 변하면 → 비교 후 true
Scaffold 에서 최상단에 배치되는 위젯
leading, title, actions, flexibleSpace, bottom 의 영역으로 나뉘며 AppBar의 속성에서 사용

iOS 스타일 확인 다이얼로그(CupertinoAlertDialog)
화면 위에 모달 다이얼로그를 띄워 사용자에게 예약 여부를 확인
iOS 디자인을 따르는 Cupertino 계열 위젯 사용
showCupertinoDialog(
context: context,
builder: (context) { ... },
);
Cupertino 스타일의 다이얼로그를 화면에 표시
showDialog의 iOS 버전
바깥 영역 터치해도 닫히지 않음 (강제 선택 유도)
Android에서도 사용 가능하지만 iOS UI임
builder: (context) {
return CupertinoAlertDialog(...);
}
실제로 띄울 다이얼로그 위젯을 반환
새로운 BuildContext를 받음 (다이얼로그 전용 context)
CupertinoAlertDialog(
title: Text("예약 확인"),
content: Text("예약 하시겠습니까?"),
actions: [...],
);
| 속성 | 설명 |
|---|---|
title | 다이얼로그 제목 |
content | 본문 설명 |
actions | 하단 버튼 영역 |
actions: [
CupertinoDialogAction(...),
CupertinoDialogAction(...),
],
iOS 스타일 버튼
보통 취소 / 확인 같은 선택지 구성
CupertinoDialogAction(
isDefaultAction: true,
onPressed: () {
Navigator.of(context).pop();
},
child: Text("취소"),
),
Navigator.pop()
→ 현재 다이얼로그를 닫음
isDefaultAction: true
→ iOS에서 강조 스타일 적용


영화관 좌석 선택하는 것처럼 좌석 선택 -> 예약 버튼 누르면 CupertinoDialog 띄우기까지 구현
오늘부터 Flutter 기초 과정을 다시 처음부터 시작한다. 예전에 한 번 훑었던 내용이지만 다시 기초부터 하나씩 제대로 이해하면서 튼튼하게 쌓아가려고 한다. 우선 목표는 강의를 최대한 빠르게, 하지만 흐름을 놓치지 않으면서 완강하는 것이다. 그 다음에는 바로 과제에 들어가서 실제로 코드로 부딪혀 보면서 익힌 내용을 내 것으로 만들고 싶다.