311单周赛
时间:2022.09.18
【过程】
前两道题很快就写出来了
第三道题,很难受,一种感觉能写出来但是就是写不出来的感觉,还是对于二叉树的递归不够深入
第四道题用常规方法写出来,但是超时...
6181.
最长的字母序连续子字符串的长度
题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int longestContinuousSubstring (String s) { int maxLen = 0 ; int need = s.charAt(0 ); int cnt = 0 ; for (int i = 0 ; i < s.length(); i++){ char c = s.charAt(i); if (c == need){ cnt ++; need ++; } else { need = c + 1 ; cnt = 1 ; } maxLen = Math.max(maxLen, cnt); } return maxLen; }
6182. 反转二叉树的奇数层
题目
【答题】
解题过程中,想过递归和队列两种方式。
但是,递归想的一直都是如何交换节点,所以很快就放弃了
使用队列,想的是在奇数层用遍历将值倒过来,写的过程中不是很顺利
【思路】
核心思想就是交换值,不交换结点
DFS 递归
其实使用DFS递归的过程中只要交换结点的值就可以了,这样就不会影响下面的子节点,只要考虑如何递归能够将一层的结点值倒过来。
运用到二叉树递归的一个技巧,【当递归函数参数只有一个结点难以实现递归时,可以考虑使用两个结点参数的递归函数】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public TreeNode reverseOddLevels (TreeNode root) { }private TreeNode reverseOddLevelsByDFS (TreeNode root) { dfs(root.left, root.right, 1 ); return root; }private void dfs (TreeNode node1, TreeNode node2, int level) { if (node1 == null ) return ; if (level % 2 == 1 ) { int tmp = node1.val; node1.val = node2.val; node2.val = tmp; } dfs(node1.left, node2.right, level+1 ); dfs(node1.right, node2.left, level+1 ); }
BFS 迭代
BFS迭代就是借助队列实现层次遍历,如果是奇数层做出对结点值的改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 int [] values;private TreeNode reverseOddLevelsByBFS (TreeNode root) { Queue<TreeNode> queue = new LinkedList <>(); queue.offer(root); int level = 0 ; while (!queue.isEmpty()){ int size = queue.size(); if (level % 2 == 1 ){ values = new int [size]; for (int i = 0 ; i < size; i++){ TreeNode node = queue.poll(); values[i] = node.val; queue.offer(node); } } for (int i = 0 ; i < size; i++){ TreeNode node = queue.poll(); if (level % 2 == 1 ){ node.val = values[size - i - 1 ]; } if (node.left != null ) queue.offer(node.left); if (node.right != null ) queue.offer(node.right); } level++; } return root; }
6183. 字符串的前缀分数和
题目
在前缀树的基础上,这道题就十分简单了,只需要稍微改造一下前缀树,在插入word的过程中每经过一个结点就+1,然后再提供一个计算word得分的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public int [] sumPrefixScores(String[] words) { Trie root = new Trie (); for (String word : words) { root.insert(word); } int [] answer = new int [words.length]; for (int i = 0 ; i < words.length; i++) { answer[i] = root.getScores(words[i]); } return answer; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 class Trie { public Trie[] children; boolean isEnd; public int cnt; public Trie () { children = new Trie [26 ]; isEnd = false ; cnt = 0 ; } public void insert (String word) { Trie cur = this ; for (int i = 0 ; i < word.length(); i++){ char c = word.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ) { cur.children[idx] = new Trie (); } cur.children[idx].cnt ++; cur = cur.children[idx]; } cur.isEnd = true ; } public int getScores (String word) { Trie cur = this ; int score = 0 ; for (int i = 0 ; i < word.length(); i++){ char c = word.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ){ return 0 ; } else { score += cur.children[idx].cnt; cur = cur.children[idx]; } } return score; } public boolean search (String word) { Trie cur = this ; for (int i = 0 ; i < word.length(); i++){ char c = word.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ){ return false ; } else { cur = cur.children[idx]; } } return cur.isEnd; } public boolean startsWith (String prefix) { Trie cur = this ; for (int i = 0 ; i < prefix.length(); i++){ char c = prefix.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ){ return false ; } else { cur = cur.children[idx]; } } return true ; } }
模板: 208. 实现 Trie (前缀树)
题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class Trie { public Trie[] children; boolean isEnd; public Trie () { children = new Trie [26 ]; isEnd = false ; cnt = 0 ; } public void insert (String word) { Trie cur = this ; for (int i = 0 ; i < word.length(); i++){ char c = word.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ) { cur.children[idx] = new Trie (); } cur = cur.children[idx]; } cur.isEnd = true ; } public boolean search (String word) { Trie cur = this ; for (int i = 0 ; i < word.length(); i++){ char c = word.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ){ return false ; } else { cur = cur.children[idx]; } } return cur.isEnd; } public boolean startsWith (String prefix) { Trie cur = this ; for (int i = 0 ; i < prefix.length(); i++){ char c = prefix.charAt(i); int idx = c - 'a' ; if (cur.children[idx] == null ){ return false ; } else { cur = cur.children[idx]; } } return true ; } }
327单周赛
时间:2023-01-08
在第三道题浪费了太多时间,第四道题比较复杂,思路不清晰。
这道题在做题时把问题想简单了,导致没有考虑全面,通过判题罚时找到漏洞。
其实可以将两个字符串的字符出现情况用两个数组记录下来,然后双重循环即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 bool isItPossible (string word1, string word2) { vector<int > a1 (26 ) ; vector<int > a2 (26 ) ; for (char c : word1) a1[c-'a' ] ++; for (char c : word2) a2[c-'a' ] ++; int s1 = 0 , s2 = 0 ; for (int i : a1) s1 += i > 0 ; for (int i : a2) s2 += i > 0 ; if (abs (s1 - s2) > 2 ) return false ; for (int i = 0 ; i < 26 ; i++){ for (int j = 0 ; j < 26 ; j++){ if (a1[i] > 0 && a2[j] > 0 ){ a1[j]++; a1[i]--; a2[j]--; a2[i]++; s1 = 0 ; s2 = 0 ; for (int k : a1) s1 += k > 0 ; for (int k : a2) s2 += k > 0 ; if (s1 == s2) return true ; a1[j]--; a1[i]++; a2[j]++; a2[i]--; } } } return false ; }
看了题解,核心就是四个堆 ,因为上面的流程无非就是四个步骤:从桥的左边到右边、从旧仓库取箱子、从桥的右边到左边、从新仓库放箱子,就可以对应这四个步骤建立四个堆。整个过程还是比较复杂的,需要仔细理解。
==wait_l==:在桥左边等待的工人
==wait_r==:在桥右边等待的工人
==box_l==:在新仓库放箱子的工人
==box_r==:在旧仓库取箱子的工人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 typedef pair<int , int > p;int findCrossingTime (int n, int k, vector<vector<int >>& time) { int size = time.size (); for (int i = 0 ; i < size; i ++) time[i].push_back (i); sort (time.begin (), time.end (), [](vector<int >& a, vector<int >& b){ int prof_a = a[0 ] + a[2 ]; int prof_b = b[0 ] + b[2 ]; if (prof_a != prof_b) return prof_a < prof_b; return a[4 ] < b[4 ]; }); priority_queue<int > wait_l, wait_r; priority_queue<p, vector<p>, greater<p>> box_l, box_r; int cur = 0 ; for (int i = 0 ; i < k; i ++) wait_l.push (i); while (true ) { bool LtoR = n > 0 && !wait_l.empty (); bool RtoL = !wait_r.empty (); if (!LtoR && !RtoL) { int x = INT_MAX; if (!box_l.empty ()) x = min (x, box_l.top ().first); if (!box_r.empty ()) x = min (x, box_r.top ().first); cur = x; } if (RtoL){ int x = wait_r.top (); wait_r.pop (); cur += time[x][2 ]; if (n == 0 && wait_r.empty () && box_r.empty ()) return cur; box_l.push (p (cur+time[x][3 ], x)); } else if (LtoR) { int x = wait_l.top (); wait_l.pop (); cur += time[x][0 ]; box_r.push (p (cur+time[x][1 ], x)); n--; } while (!box_l.empty ()) { p worker = box_l.top (); if (worker.first > cur) break ; box_l.pop (); wait_l.push (worker.second); } while (!box_r.empty ()) { p worker = box_r.top (); if (worker.first > cur) break ; box_r.pop (); wait_r.push (worker.second); } } }
类似的题目:
1834.
单线程 CPU