diff --git a/best-time-to-buy-and-sell-stock/Tessa1217.java b/best-time-to-buy-and-sell-stock/Tessa1217.java new file mode 100644 index 000000000..7fb31ee57 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/Tessa1217.java @@ -0,0 +1,33 @@ +/** + * 주식 가격이 주어지는 prices 배열이 있을 때 최대 주식 이익을 구하시오 + * 주식을 산 날짜에는 팔 수 없으며 반드시 산 날짜의 이후 날짜부터(미래부터) 팔 수 있다. + */ +class Solution { + public int maxProfit(int[] prices) { + int maxProfit = 0; + int min = prices[0]; + // 굳이 DP 배열 쓰지 않고 계산, 공간 복잡도 낮추기 + for (int i = 0; i < prices.length; i++) { + int profit = prices[i] - min; + maxProfit = Math.max(profit, maxProfit); + min = Math.min(prices[i], min); + } + return maxProfit; + } + + // public int maxProfit(int[] prices) { + // // 최저 구매 + // int[] dp = new int[prices.length]; + // dp[0] = prices[0]; + // for (int i = 1; i < prices.length; i++) { + // dp[i] = Math.min(prices[i], dp[i - 1]); + // } + // // 최저 구매 배열 기준으로 당일 최대 이익 계산 + // int profit = 0; + // for (int i = 1; i < prices.length; i++) { + // profit = Math.max(prices[i] - dp[i - 1], profit); + // } + // return profit; + // } +} + diff --git a/encode-and-decode-strings/Tessa1217.java b/encode-and-decode-strings/Tessa1217.java new file mode 100644 index 000000000..c79ed6c24 --- /dev/null +++ b/encode-and-decode-strings/Tessa1217.java @@ -0,0 +1,39 @@ +/** + * 문자열에 대한 encode, decode 알고리즘 디자인 + * 문자열은 ASCII 256 모두 포함 가능 (문자만 포함한 게 아니므로 특수문자(:, ?) 등도 알고리즘 내에서 고려해야 함 + * */ + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + + public static String encode(List strs) { + StringBuilder sb = new StringBuilder(); + for (String str : strs) { + // : 구분자 앞에 단어의 길이 추가 + sb.append(str.length()).append(":").append(str); + } + return sb.toString(); + } + + public static List decode(String str) { + List words = new ArrayList<>(); + int i = 0; + while (i < str.length()) { + // 구분자 기준 인덱스 + int colonIdx = str.indexOf(':', i); + // 단어의 길이 인덱스 + int length = Integer.parseInt(str.substring(i, colonIdx)); + // 단어 시작 + int wordStart = colonIdx + 1; + // 단어의 끝 + int wordEnd = wordStart + length; + words.add(str.substring(wordStart, wordEnd)); + i = wordEnd; + } + return words; + } + +} + diff --git a/group-anagrams/Tessa1217.java b/group-anagrams/Tessa1217.java new file mode 100644 index 000000000..c7e8c4639 --- /dev/null +++ b/group-anagrams/Tessa1217.java @@ -0,0 +1,21 @@ +/** + * 문자열 배열 strs가 주어질 때 애너그램인 문자들끼리 묶어서 반환하세요. + */ +class Solution { + // 시간복잡도: O(n * L log L) + public List> groupAnagrams(String[] strs) { + Map> anagramMap = new HashMap<>(); + for (String str : strs) { + char[] word = str.toCharArray(); + Arrays.sort(word); + String sortedCharacter = String.valueOf(word); + if (!anagramMap.containsKey(sortedCharacter)) { + anagramMap.put(sortedCharacter, new ArrayList<>()); + } + anagramMap.get(sortedCharacter).add(str); + } + return new ArrayList(anagramMap.values()); + } + +} + diff --git a/implement-trie-prefix-tree/Tessa1217.java b/implement-trie-prefix-tree/Tessa1217.java new file mode 100644 index 000000000..813dd23cf --- /dev/null +++ b/implement-trie-prefix-tree/Tessa1217.java @@ -0,0 +1,86 @@ +/** + * trie는 효율적으로 데이터를 저장하고 키를 통해 문자열 데이터 셋을 검색할 수 있는 트리 구조이다. + * 해당 구조를 활용해 자동완성이나 스펠링 체크를 만들 수 있다. + trie 클래스는 다음과 같이 구현할 수 있다. + Trie() 클래스 생성자 + void insert(String word) : trie로 문자열 word를 삽입 + boolean search(String word) : 문자열 word가 trie에 있다면 true를 반환 + boolean startsWith(String prefix) : prefix가 trie에 있다면 true를 반환 + */ +class Trie { + + private Node root; + + public Trie() { + root = new Node(); + } + + public void insert(String word) { + Node current = root; + for (char c : word.toCharArray()) { + if (!current.getNodeCharacters().containsKey(c)) { + current.getNodeCharacters().put(c, new Node()); + } + current = current.getNodeCharacters().get(c); + } + current.setEnd(); + } + + public boolean search(String word) { + Node current = root; + for (char c : word.toCharArray()) { + if (!current.getNodeCharacters().containsKey(c)) { + return false; + } + current = current.getNodeCharacters().get(c); + } + return current.getEnd(); + } + + public boolean startsWith(String prefix) { + Node current = root; + for (char c : prefix.toCharArray()) { + if (!current.getNodeCharacters().containsKey(c)) { + return false; + } + current = current.getNodeCharacters().get(c); + } + return true; + } + + static class Node { + + // 문자열 끝 여부 + private boolean isEnd; + + // 키 추출을 위한 맵 구조 + private Map nodeCharacters; + + Node() { + nodeCharacters = new HashMap<>(); + isEnd = false; + } + + public boolean getEnd() { + return this.isEnd; + } + + public void setEnd() { + this.isEnd = true; + } + + public Map getNodeCharacters() { + return this.nodeCharacters; + } + + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ + diff --git a/word-break/Tessa1217.java b/word-break/Tessa1217.java new file mode 100644 index 000000000..263ea5d42 --- /dev/null +++ b/word-break/Tessa1217.java @@ -0,0 +1,25 @@ +/** + * 문자열 s가 주어질 때 wordDict의 단어 문자열로 s가 구성될 수 있는지 여부를 반환하세요. + */ +class Solution { + public boolean wordBreak(String s, List wordDict) { + int n = s.length(); + boolean[] dp = new boolean[n + 1]; + dp[0] = true; + + // contains 최적화를 위해 Set 선언: 시간 복잡도: O(n^2) + Set wordSet = new HashSet<>(wordDict); + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < i; j++) { + String word = s.substring(j, i); + if (dp[j] && wordSet.contains(word)) { + dp[i] = true; + break; + } + } + } + return dp[n]; + } +} +