1,递增序列
220,存在重复元素 III
题目:给你一个整数数组
nums和两个整数k和t。请你判断是否存在 两个不同下标i和j,使得abs(nums[i] - nums[j]) <= t,同时又满足abs(i - j) <= k。如果存在则返回true,不存在返回false。思路:滑动窗口+排序树
class Solution { public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { int n = nums.length; TreeSet<Long> set = new TreeSet<Long>(); for (int i = 0; i < n; i++) { Long ceiling = set.ceiling((long) nums[i] - (long) t); if (ceiling != null && ceiling <= (long) nums[i] + (long) t) { return true; } set.add((long) nums[i]); if (i >= k) { set.remove((long) nums[i - k]); } } return false; } }
334,递增的三元子序列(123模式)
题目:给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。
class Solution { public boolean increasingTriplet(int[] nums) { int a = 2147483647, b = a; for (int n: nums) if (n <= a) a = n; else if (n <= b) b = n; else return true; return false; } }
456,132模式
题目:给你一个整数数组
nums,数组中共有n个整数。132 模式的子序列 由三个整数nums[i]、nums[j]和nums[k]组成,并同时满足:i < j < k和nums[i] < nums[k] < nums[j]。如果nums中存在 132 模式的子序列 ,返回true;否则,返回false。
class Solution { public boolean find132pattern(int[] nums) { int n = nums.length; Deque<Integer> candidateK = new LinkedList<Integer>(); candidateK.push(nums[n - 1]); int maxK = Integer.MIN_VALUE; for (int i = n - 2; i >= 0; --i) { if (nums[i] < maxK) { return true; } while (!candidateK.isEmpty() && nums[i] > candidateK.peek()) { maxK = candidateK.pop(); } if (nums[i] > maxK) { candidateK.push(nums[i]); } } return false; } }
1855,12模式(下标对中最大距离)
题目:给你两个 非递增 的整数数组 nums1 和 nums2 ,数组下标均 从 0 开始 计数。下标对 (i, j) 中 0 <= i < nums1.length 且 0 <= j < nums2.length 。如果该下标对同时满足 i <=j 且 nums1[i] <= nums2[j] ,则称之为 有效 下标对,该下标对的 距离 为 j - i 。返回所有 有效 下标对 (i, j) 中的 最大距离 。如果不存在有效下标对,返回 0 。
class Solution { public int maxDistance(int[] nums1, int[] nums2) { int left = 0; int right = 0; int result = 0; while (left < nums1.length && right < nums2.length) { if (left < right && nums1[left] <= nums2[right]) { result = Math.max(result, right - left); right++; } else if (left < right && nums1[left] > nums2[right]) { left++; } else if (left > right) { right++; } else if (left == right && nums1[left] <= nums2[right]) { result = Math.max(result, right - left); right++; } else if (left == right && nums1[left] > nums2[right]) { left++; } } return result; } }
2,字典树(前缀树)
208,实现Trie(前缀树)
题目:Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:
Trie()初始化前缀树对象。void insert(String word)向前缀树中插入字符串word。boolean search(String word)如果字符串word在前缀树中,返回true(即,在检索之前已经插入);否则,返回false。boolean startsWith(String prefix)如果之前已经插入的字符串word的前缀之一为prefix,返回true;否则,返回false。思路:
class Trie { private Trie[] children; private boolean isEnd; public Trie() { children = new Trie[26]; isEnd = false; } public void insert(String word) { Trie node = this; for (int i = 0; i < word.length(); i++) { char ch = word.charAt(i); int index = ch - 'a'; if (node.children[index] == null) { node.children[index] = new Trie(); } node = node.children[index]; } node.isEnd = true; } public boolean search(String word) { Trie node = searchPrefix(word); return node != null && node.isEnd; } public boolean startsWith(String prefix) { return searchPrefix(prefix) != null; } private Trie searchPrefix(String prefix) { Trie node = this; for (int i = 0; i < prefix.length(); i++) { char ch = prefix.charAt(i); int index = ch - 'a'; if (node.children[index] == null) { return null; } node = node.children[index]; } return node; } }
421,数组中两个数的最大异或值
题目:给你一个整数数组
nums,返回nums[i] XOR nums[j]的最大运算结果,其中0 ≤ i ≤ j < n。class Solution { public int findMaximumXOR(int[] nums) { int max = 0; // 两个非负数的异或必为非负数 Trie trie = new Trie(); for(int num : nums){ trie.insert(num); max = Math.max(max, num ^ trie.search(num)); } return max; } } class Trie{ Trie[] next; public Trie(){ this.next = new Trie[2]; } public void insert(int num){ Trie cur = this; for(int i = 30; i >= 0; i--){ // 题目范围为非负数,高31位移动到低1位只要右移30位 int bit = (num >> i) & 1; if(cur.next[bit] == null){ cur.next[bit] = new Trie(); } cur = cur.next[bit]; } } public int search(int num){ // 返回当前前缀树中与num做异或能够取得最大值的数字。取出后再在外部做异或运算。 Trie cur = this; int ans = 0; for(int i = 30; i >= 0; i--){ int bit = (num >> i) & 1; // 取得当前位(0或1) bit = cur.next[bit ^ 1] == null ? bit : bit ^ 1; // 与bit相反(指0-1相反)的节点若不存在,bit不变,若存在,取相反 ans += bit << i; // 累计ans cur = cur.next[bit]; } return ans; } }
648,单词替换
题目:在英语中,我们有一个叫做
词根(root) 的概念,可以词根后面添加其他一些词组成另一个较长的单词——我们称这个词为继承词(successor)。例如,词根an,跟随着单词other(其他),可以形成新的单词another(另一个)。现在,给定一个由许多词根组成的词典
dictionary和一个用空格分隔单词形成的句子sentence。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。你需要输出替换之后的句子。
class Solution { class TrieNode{ TrieNode[] next; String word; public TrieNode(){ this.next = new TrieNode[26]; this.word = null; } } private TrieNode tRoot = new TrieNode(); public String replaceWords(List<String> dictionary, String sentence) { //先将所有的词根加入到Trie中 for(String s : dictionary){ add(s); } //拆分sentence String[] sp = sentence.split(" "); //遍历sp,在Trie中搜索是否有可以替代的词根 for(int i = 0;i < sp.length;i++){ String root = get(sp[i]); //如果root不为null则找到了可以替代的词根,将此处的原单词替换为词根 if(root != null){ sp[i] = root; } } //最后再把sp数组用空格分隔拼接成一个串返回即可 return String.join(" ",sp); } public void add(String str){ TrieNode node = tRoot; for(char c : str.toCharArray()){ if(node.next[c - 'a'] == null){ node.next[c - 'a'] = new TrieNode(); } node = node.next[c - 'a']; } //把整个单词都加进Trie中之后,在最后面挂上word node.word = str; } public String get(String str){ TrieNode node = tRoot; for(char c : str.toCharArray()){ //如果遇到了词根了,直接break,此时遇到的词根符合题目“最短词根的要求” if(node.word != null){ break; } //走到这里就是还没遇到词根,如果在没遇到词根就不满足条件了,直接返回null if(node.next[c - 'a'] == null){ return null; } //迭代 node = node.next[c - 'a']; } return node.word; } }
676,实现一个魔法字典
题目:设计一个使用单词列表进行初始化的数据结构,单词列表中的单词 互不相同 。 如果给出一个单词,请判定能否只将这个单词中一个字母换成另一个字母,使得所形成的新单词存在于你构建的字典中。
实现
MagicDictionary类:
MagicDictionary()初始化对象void buildDict(String[] dictionary)使用字符串数组dictionary设定该数据结构,dictionary中的字符串互不相同bool search(String searchWord)给定一个字符串searchWord,判定能否只将字符串中 一个 字母换成另一个字母,使得所形成的新字符串能够与字典中的任一字符串匹配。如果可以,返回true;否则,返回false。class MagicDictionary { HashMap<String, Integer> map; HashSet<String> set; /** Initialize your data structure here. */ public MagicDictionary() { map = new HashMap<>(); set = new HashSet<>(); } public void buildDict(String[] dictionary) { for(String s: dictionary){ set.add(s); StringBuffer sb = new StringBuffer(s); for(int i=0; i<sb.length(); i++){ sb.setCharAt(i, '*'); map.put(sb.toString(), map.getOrDefault(sb.toString(), 0)+1); sb.setCharAt(i, s.charAt(i)); } } } public boolean search(String searchWord) { StringBuffer sb = new StringBuffer(searchWord); for(int i=0; i<sb.length(); i++){ sb.setCharAt(i, '*'); String s = sb.toString(); if(map.containsKey(s)){ if(map.get(s) > 1) return true; if(map.get(s) == 1 && !set.contains(searchWord)) return true; } sb.setCharAt(i, searchWord.charAt(i)); } return false; } }
677,键值映射
题目:设计一个 map ,满足以下几点:
- 字符串表示键,整数表示值
- 返回具有前缀等于给定字符串的键的值的总和
实现一个
MapSum类:
MapSum()初始化MapSum对象void insert(String key, int val)插入key-val键值对,字符串表示键key,整数表示值val。如果键key已经存在,那么原来的键值对key-value将被替代成新的键值对。int sum(string prefix)返回所有以该前缀prefix开头的键key的值的总和。class MapSum { class TreeNode{ boolean isEnd; int val; TreeNode[] tns = new TreeNode[26]; } TreeNode root; int sum; public MapSum() { root = new TreeNode(); } public void insert(String key, int val) { TreeNode p = root; for(char ch : key.toCharArray()){ int temp = ch - 'a'; if(p.tns[temp] == null){ p.tns[temp] = new TreeNode(); } p = p.tns[temp]; } p.isEnd = true; p.val = val; } public int sum(String prefix) { sum = 0; TreeNode p = root; for(char ch : prefix.toCharArray()){ int temp = ch - 'a'; if(p.tns[temp] == null){ return sum; } p = p.tns[temp]; } find(p); return sum; } public void find(TreeNode p){ if(p.isEnd == true){ sum += p.val; } for(int i = 0;i < 26;i++){ if(p.tns[i] != null){ find(p.tns[i]); } } return; } }
720,词典中最长的单词
题目:给出一个字符串数组
words组成的一本英语词典。返回words中最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。class Solution { public String longestWord(String[] words) { Arrays.sort(words); String ans = ""; Trie trie = new Trie(); for (String s : words) { trie.insert(s); if (trie.inDictionary(s) && s.length() > ans.length()) { ans = s; } } return ans; } } class Trie { TrieNode root; public Trie() { root = new TrieNode(); } void insert(String s) { TrieNode cur = root; for (char c : s.toCharArray()) { if (cur.children[c - 'a'] == null) { cur.children[c - 'a'] = new TrieNode(); } cur = cur.children[c - 'a']; } cur.exist = true; } boolean inDictionary(String s) { TrieNode cur = root; for (char c : s.toCharArray()) { cur = cur.children[c - 'a']; if (cur == null || !cur.exist) { return false; } } return true; } } class TrieNode { boolean exist; TrieNode[] children; TrieNode() { exist = false; children = new TrieNode[26]; } }
820,单词的压缩编码
题目:单词数组
words的 有效编码 由任意助记字符串s和下标数组indices组成,且满足:
words.length == indices.length- 助记字符串
s以'#'字符结尾- 对于每个下标
indices[i],s的一个从indices[i]开始、到下一个'#'字符结束(但不包括'#')的 子字符串 恰好与words[i]相等给你一个单词数组
words,返回成功对words进行编码的最小助记字符串s的长度 。思路:目标就是保留所有不是其他单词后缀的单词。
class Solution { public int minimumLengthEncoding(String[] words) { TrieNode trie = new TrieNode(); Map<TrieNode, Integer> nodes = new HashMap<TrieNode, Integer>(); for (int i = 0; i < words.length; ++i) { String word = words[i]; TrieNode cur = trie; for (int j = word.length() - 1; j >= 0; --j) { cur = cur.get(word.charAt(j)); } nodes.put(cur, i); } int ans = 0; for (TrieNode node: nodes.keySet()) { if (node.count == 0) { ans += words[nodes.get(node)].length() + 1; } } return ans; } } class TrieNode { TrieNode[] children; int count; TrieNode() { children = new TrieNode[26]; count = 0; } public TrieNode get(char c) { if (children[c - 'a'] == null) { children[c - 'a'] = new TrieNode(); count++; } return children[c - 'a']; } }
最后
以上就是受伤中心最近收集整理的关于LeetCode:排序树,字典树的全部内容,更多相关LeetCode:排序树内容请搜索靠谱客的其他文章。


发表评论 取消回复