From c026aedc3f90de60b87c8a7f265cf831dced2cdb Mon Sep 17 00:00:00 2001 From: dongha kim Date: Sat, 11 Jan 2025 23:29:48 +0900 Subject: [PATCH] feat : week 5 --- .../imsosleepy.java | 40 ++++++++ encode-and-decode-strings/imsosleepy.java | 61 ++++++++++++ group-anagrams/imsosleepy.java | 16 ++++ implement-trie-prefix-tree/imsosleepy.java | 92 +++++++++++++++++++ word-break/imsosleepy.java | 20 ++++ 5 files changed, 229 insertions(+) create mode 100644 best-time-to-buy-and-sell-stock/imsosleepy.java create mode 100644 encode-and-decode-strings/imsosleepy.java create mode 100644 group-anagrams/imsosleepy.java create mode 100644 implement-trie-prefix-tree/imsosleepy.java create mode 100644 word-break/imsosleepy.java diff --git a/best-time-to-buy-and-sell-stock/imsosleepy.java b/best-time-to-buy-and-sell-stock/imsosleepy.java new file mode 100644 index 000000000..0a75624c3 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/imsosleepy.java @@ -0,0 +1,40 @@ +// 투포인터를 쓸 필요 없음. 그냥 최소값을 찾아 빼주면 O(N)의 시간 복잡도를 얻을 수 있다. +// 투포인터와 큰 차이가 없는 이유는 투포인터도 O(N)이기 때문. 아주 약간의 공간복잡도 차이만 있을 듯 +// 결과는 큰 차이 없으나 알고리즘 자체가 더 쉽다. +class Solution { + public int maxProfit(int[] prices) { + int minPrice = Integer.MAX_VALUE; + int maxProfit = 0; + + for (int price : prices) { + if (price < minPrice) { + minPrice = price; + } else { + maxProfit = Math.max(maxProfit, price - minPrice); + } + } + + return maxProfit; + } +} + +// 처음 생각한 투포인터 방식 +class Solution { + public int maxProfit(int[] prices) { + int left = 0; + int right = 1; + int maxProfit = 0; + + while (right < prices.length) { + if (prices[left] < prices[right]) { + int profit = prices[right] - prices[left]; + maxProfit = Math.max(maxProfit, profit); + } else { + left = right; + } + right++; + } + + return maxProfit; + } +} diff --git a/encode-and-decode-strings/imsosleepy.java b/encode-and-decode-strings/imsosleepy.java new file mode 100644 index 000000000..b74babd1d --- /dev/null +++ b/encode-and-decode-strings/imsosleepy.java @@ -0,0 +1,61 @@ +// 아이디어로 푸는 문제라 선호하지 않는 문제... +// 그냥 사용하지 않는 것을 구분자로 두고 스플릿하는게 가장 편하다. 아예 나오지 않을 문자를 기준으로 두면 길이를 알 필요가 없기 때문 +public class Solution { + // 인코딩 메서드 + public String encode(List strs) { + StringBuilder encodedString = new StringBuilder(); + + for (String str : strs) { + encodedString.append(str.length()).append("#").append(str); + } + + return encodedString.toString(); + } + + // 디코딩 메서드 + public List decode(String s) { + List decodedList = new ArrayList<>(); + int i = 0; + + while (i < s.length()) { + + int j = i; + while (s.charAt(j) != '#') { + j++; + } + + int length = Integer.parseInt(s.substring(i, j)); + decodedList.add(s.substring(j + 1, j + 1 + length)); + + i = j + 1 + length; + } + + return decodedList; + } +} +// 🚀를 기준으로 문자열을 분리 +// @!#$@#$ 이런걸 스플릿 문자로 두는 방법도 있다.아이온 +public class Solution { + + public String encode(List strs) { + StringBuilder encodedString = new StringBuilder(); + + for (String str : strs) { + encodedString.append(str).append("🚀"); + } + + return encodedString.toString(); + } + + public List decode(String s) { + String[] parts = s.split("🚀"); + List decodedList = new ArrayList<>(); + for (String part : parts) { + if (!part.isEmpty()) { + decodedList.add(part); + } + } + + return decodedList; + } +} diff --git a/group-anagrams/imsosleepy.java b/group-anagrams/imsosleepy.java new file mode 100644 index 000000000..9dc412ae3 --- /dev/null +++ b/group-anagrams/imsosleepy.java @@ -0,0 +1,16 @@ +// 모든 단어를 정렬해야하기 때문에 시간 복잡도가 꽤 나오는 문제 +// 하지만 모든 단어를 정렬해도 된다는건 글자 수가 100자 제한이 있어서 유추할 수 있다. +// O(N) * O(MlogM) N 배열 길이, M 글자수의 시간복잡도가 나옴 +class Solution { + public List> groupAnagrams(String[] strs) { + HashMap> anagrams = new HashMap<>(); + for(String str: strs) { + char[] charArray = str.toCharArray(); + Arrays.sort(charArray); + String sortedWord = new String(charArray); + anagrams.computeIfAbsent(sortedWord, k -> new ArrayList<>()).add(str); + } + + return new ArrayList<>(anagrams.values()); + } +} diff --git a/implement-trie-prefix-tree/imsosleepy.java b/implement-trie-prefix-tree/imsosleepy.java new file mode 100644 index 000000000..2552658b5 --- /dev/null +++ b/implement-trie-prefix-tree/imsosleepy.java @@ -0,0 +1,92 @@ +// GPT의 풀이. 트리를 이용해 O(m)으로 해결했다. +public class Trie { + private class TrieNode { + TrieNode[] children; + boolean isEndOfWord; + + public TrieNode() { + children = new TrieNode[26]; // 알파벳 a~z (26개의 자식 노드) + isEndOfWord = false; // 해당 노드가 단어의 끝인지 아닌지 나타냄 + } + } + + private TrieNode root; + + public Trie() { + root = new TrieNode(); // 루트 노드 초기화 + } + + public void insert(String word) { + TrieNode node = root; + for (char c : word.toCharArray()) { + int index = c - 'a'; // 알파벳을 0-25의 숫자로 변환 + if (node.children[index] == null) { + node.children[index] = new TrieNode(); // 해당 문자가 없으면 새 노드를 생성 + } + node = node.children[index]; // 자식 노드로 이동 + } + node.isEndOfWord = true; // 단어의 끝을 표시 + } + + public boolean search(String word) { + TrieNode node = root; + for (char c : word.toCharArray()) { + int index = c - 'a'; + if (node.children[index] == null) { + return false; // 해당 문자가 없으면 false 반환 + } + node = node.children[index]; // 자식 노드로 이동 + } + return node.isEndOfWord; // 단어의 끝인지를 확인 + } + + public boolean startsWith(String prefix) { + TrieNode node = root; + for (char c : prefix.toCharArray()) { + int index = c - 'a'; + if (node.children[index] == null) { + return false; // 해당 접두사로 시작하는 단어가 없으면 false 반환 + } + node = node.children[index]; // 자식 노드로 이동 + } + return true; // 접두사로 시작하는 단어가 있으면 true 반환 + } +} + +// 백트래킹으로 풀어봤는데, 속도가 너무 안나왔음 +// O(n*m)의 시간복잡도가 나옴. n은 글자수 m은 글자길이 +class Trie { + + private List words; + + public Trie() { + words = new ArrayList<>(); + } + + public void insert(String word) { + words.add(word); + } + + public boolean search(String word) { + return backtrack(word, true); + } + + public boolean startsWith(String prefix) { + return backtrack(prefix, false); + } + + private boolean backtrack(String target, boolean exactMatch) { + for (String word : words) { + if (exactMatch) { + if (word.equals(target)) { + return true; + } + } else { + if (word.startsWith(target)) { + return true; + } + } + } + return false; + } +} diff --git a/word-break/imsosleepy.java b/word-break/imsosleepy.java new file mode 100644 index 000000000..80e02524c --- /dev/null +++ b/word-break/imsosleepy.java @@ -0,0 +1,20 @@ +// dp 배열 (dp[i] = s[0...i]가 단어들로 나눠질 수 있는지 여부) +// 입력 데이터의 크기가 크지 않아서 O(N^2)도 가능한 문제. +class Solution { + public boolean wordBreak(String s, List wordDict) { + Set wordSet = new HashSet<>(wordDict); + boolean[] dp = new boolean[s.length() + 1]; + dp[0] = true; + + for (int i = 1; i <= s.length(); i++) { + for (int j = 0; j < i; j++) { + if (dp[j] && wordSet.contains(s.substring(j, i))) { + dp[i] = true; + break; + } + } + } + + return dp[s.length()]; + } +}