기존의 양과 늑대코드를 조금 리팩토링하였다.
import java.util.*;
class Solution {
private static final int SHEEP = 0;
public int solution(int[] info, int[][] edges) {
Map<Integer, Node> nodes = getNodes(info);
weave(edges, nodes);
Node root = nodes.get(0);
LinkedHashSet<Node> nexts = getNextVisitableNodesFrom(root, new LinkedHashSet<>());
return getMaxSheepCount(root, nexts, 0, 0);
}
private Map<Integer, Node> getNodes(int[] info) {
Map<Integer, Node> nodes = new HashMap<>();
for (int i = 0; i < info.length; i++) {
nodes.put(i, new Node(i, info[i]));
}
return nodes;
}
private void weave(int[][] edges, Map<Integer, Node> nodes) {
for (int[] edge : edges) {
Node parent = nodes.get(edge[0]);
Node child = nodes.get(edge[1]);
parent.setChild(child);
}
}
private int getMaxSheepCount(Node node, LinkedHashSet<Node> visitableNodes, int sheepCnt, int wolfCnt) {
if (node.TYPE == SHEEP) {
sheepCnt++;
} else {
wolfCnt++;
}
if (sheepCnt == wolfCnt) {
return 0;
}
int maxSheepCount = sheepCnt;
for (Node nextNode : visitableNodes) {
LinkedHashSet<Node> visitableNodesAfterVisitNextNode = getNextVisitableNodesFrom(nextNode, visitableNodes);
maxSheepCount = Math.max(maxSheepCount, getMaxSheepCount(nextNode, visitableNodesAfterVisitNextNode, sheepCnt, wolfCnt));
}
return maxSheepCount;
}
private LinkedHashSet<Node> getNextVisitableNodesFrom(Node from, LinkedHashSet<Node> oldVisitableNodes) {
LinkedHashSet<Node> nextVisitableNodes = new LinkedHashSet<>(oldVisitableNodes);
if (from.isNotRoot()) {
nextVisitableNodes.remove(from);
}
if (from.left != null) {
nextVisitableNodes.add(from.left);
}
if (from.right != null) {
nextVisitableNodes.add(from.right);
}
return nextVisitableNodes;
}
class Node {
final int NUMBER;
final int TYPE;
Node left;
Node right;
public Node(int NUMBER, int TYPE) {
this.NUMBER = NUMBER;
this.TYPE = TYPE;
}
public boolean isRoot() {
return NUMBER == 0;
}
public boolean isNotRoot() {
return !isRoot();
}
public void setChild(Node child){
if (this.left == null) {
this.left = child;
} else {
this.right = child;
}
}
}
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
// https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api
compileOnly group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0'
// https://mvnrepository.com/artifact/org.projectlombok/lombok
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.26'
annotationProcessor 'org.projectlombok:lombok:1.18.26'
}
톰캣설치파일/libs
rest api에선 세션을 갖지 않는다. 앞으로 인증은 클라이언트에게 JWT를 제공하는 방식으로 구현된다.
rest api는 http 메서드와 url의 조합으로 요청의 행위를 표현하는 것이 권장된다.
예시
GET
도메인/articlesPATCH
도메인/article/1POST
도메인/articleDELETE
도메인/article/1PATCH는 전체 데이터 수정, PUT은 데이터의 일부를 수정하는데에 주로 쓰인다.
과정
사용자는 Post로그인 요청을 한다. 이 때 로그인 정보는 폼데이터가 아닌 요청바디에 정해진 형식으로 보내진다.
서버는 db에서 사용자를 검색하고 사용자 정보를 담은 jwt를 응답에 담아서 보낸다.
컨트롤러
@PostMapping("/login")
public RsData<LoginResponse> login(@Valid @RequestBody LoginRequest loginRequest, HttpServletResponse resp) {
String accessToken = memberService.getAccessToken(loginRequest.getUsername(),loginRequest.getPassword());
resp.addHeader("Authentication", accessToken);
return RsData.of(
"S-1",
"액세스 토큰이 생성되었습니다.",
new LoginResponse(accessToken)
);
}
서비스
public String getAccessToken(String username, String password) {
Member member = findByUsername(username).orElse(null);
if (member==null) {
return null;
}
if (!passwordEncoder.matches(password, member.getPassword())) {
return null;
}
return jwtProvider.genToken(member.toClaims(), 60 * 60 * 24 * 365);
}