5554. 能否连接形成数组 题意 给定整数数组 arr ,其中每个整数互不相同 。另有一个由整数数组构成的数组 pieces,其中的整数也互不相同 。请以 任意顺序 连接 pieces 中的数组以形成 arr 。但是,不允许 对每个数组内部 pieces[i] 中的整数重新排序。若可连接 pieces 中的数组形成 arr ,返回 true ;否则,返回 false 。
样例 分析 如果遍历arr每个元素找到其对应的pieces[i]子数组,考虑的细节有很多。不妨遍历每个pieces[i]数组,以其子数组的首元素作为切入口,找到arr数组对应位置,再将pieces[i]这个子数组遍历完,如果无法遍历完又或者arr对应指针到达末端,则说明无法满足题目要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution {public : bool canFormArray (vector<int >& arr, vector<vector<int >>& pieces) { int tot = 0 , i = 0 ; for (; i < pieces.size (); i++){ int pos; for (pos = 0 ; pos < arr.size (); pos++){ if (arr[pos] == pieces[i][0 ]) break ; } if (pos == arr.size ()) return false ; for (int j = 0 ; j < pieces[i].size (); j++){ if (pieces[i][j] == arr[pos]) pos++; else return false ; if (pos >= arr.size () && j + 1 < pieces[i].size ()) return false ; } } return (i == pieces.size ()); } };
5555. 统计字典序元音字符串的数目 #组合数 #暴力搜索 题意 给定整数n ( ≤ 50 ) n(\le 50) n ( ≤ 50 ) ,请返回长度为n n n 、仅由元音 (a , e , i , o , u a, e, i, o, u a , e , i , o , u ) 组成且按 字典序排列 的字符串数量 。
字符串s s s 按 字典序排列 需要满足:对于所有有效的i i i ,s [ i ] s[i] s [ i ] 在字母表中的位置总是与s [ i + 1 ] s[i+1] s [ i + 1 ] 相同或在s [ i + 1 ] s[i+1] s [ i + 1 ] 之前。
分析 下面是我在比赛时交的暴搜版本(主要是因为数据规模不大),每次递归是枚举当前位置放置第i i i 个元音字母且保证不超过上一个字母。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {private : int depest = 0 ;public : int DFS (int depth, int pre) { if (depth == depest) return 1 ; int ans = 0 ; for (int i = 1 ; i <= pre; i++) ans += DFS (depth + 1 , i); return ans; } int countVowelStrings (int n) { depest = n; int ans = 0 ; for (int i = 1 ; i <= 5 ; i++) ans += DFS (1 , i); return ans; } };
仔细一想,其实我们直接用挡板法便能求出来。因为所求的字符串一定是按a ≤ e ≤ i ≤ o ≤ u a\le e\le i\le o\le u a ≤ e ≤ i ≤ o ≤ u 的顺序的,不过每种元音字母的数量可以为0 0 0 。由于隔板法需要保证每个箱子至少有一个球,那我们可以给每个元音字母分配一个虚拟的位置(即需要n + 5 n+5 n + 5 个小球),插完隔板之后再将虚拟位置去掉即可。故答案即为C n + 5 − 1 5 − 1 C^{5-1}_{n+5-1} C n + 5 − 1 5 − 1 。
1 2 3 4 5 6 class Solution {public : int countVowelStrings (int n) { return (n + 4 ) * (n + 3 ) * (n + 2 ) * (n + 1 ) / 24 ; } };
5556. 可以到达的最远建筑 #贪心 题意 给定整数数组 heights ,表示建筑物的高度。另有一些bricks个砖块 和 ladders 梯子。
你从建筑物 0 开始出发,不断向后面的建筑物移动,当从建筑物 i 移动到建筑物 i+1(下标 从 0 开始 )时:
若当前建筑物的高度 大于或等于 下一建筑物的高度,则不需要梯子或砖块。 如果当前建筑的高度 小于 下一个建筑的高度,您可以使用 一架梯子 或 (h[i+1] - h[i]) 个砖块 如果以最佳方式使用给定的梯子和砖块,返回你可以到达的最远 建筑物的下标(下标 从 0 开始 )。
分析 感谢@零神的题解 ,讲解得十分好。
我试着用自己的语言去总结下吧,题目中的梯子可以爬无限高的楼,设梯子数量为l l l ,出于贪心思想,我们一定会将所有的梯子用在前l l l 大的楼层高度差Δh h h 。但是我们不可能即时确定下来这l l l 个较大的Δh h h ,因而需要用个小根堆去维护。
为什么用小根堆?因为每次到达新的楼时,判断新的Δh h h 是否比小根堆的堆顶(即第l l l 大的Δh h h )还大,如果成立则应该将这个新的Δh h h 加入堆,并把原来的堆顶pop出来,交给砖块去跨越。
何时终止?当砖块的数量不足以解决新pop出来的Δh h h 时,算法即终止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : int furthestBuilding (vector<int >& heights, int bricks, int ladders) { priority_queue<int , vector<int >, greater<int >> myque; int brickSum = 0 ; for (int i = 0 ; i + 1 < heights.size (); i++){ int diff = heights[i + 1 ] - heights[i]; if (diff < 0 ) continue ; myque.push (diff); if (myque.size () > ladders){ brickSum += myque.top (); myque.pop (); } if (brickSum > bricks) return i; } return heights.size () - 1 ; } };
5600. 第 K 条最小指令 #组合公式 #分治 题意 Bob 站在单元格 (0, 0) ,想要前往目的地坐标 destination :(row, column) 。你可以为 Bob 提供导航 指令 来帮助他到达目的地 destination 。
指令 用字符串表示,其中每个字符:'H' ,意味着水平向右移动;'V' ,意味着竖直向下移动。 能够为 Bob 导航到目的地 destination 的指令可以有多种,例如,如果目的地 destination 是 (2, 3),"HHHVV", "HHVHV", "HHVVH", "HVHHV", ...都是有效 指令 。然而,Bob 想要遵循 按字典序 排列后的第 k 条最小指令 (从1)的导航前往目的地 destination 。例如,Bob需要第3条最小,对应指令即为"HHVVH"。
给定整数数组 destination 和一个整数 k ,现要返回这个按字典序排列后的第 k 条最小字符串指令 。
分析 再次感谢@零神的题解 orz…
设需要放入h h h 个'H'和v v v 个'V',题目要求第k k k 小,那么我们可以从高位到低位,不断淘汰出前k k k 小的串,具体如下:
我们考虑当前最高位pos,应该放'H'还是'V'。假设放'V',那么所有pos位为'H'的字符串都会被淘汰掉,且总共有c u r = C h + v − 1 h − 1 cur = C^{h-1}_{h+v-1} c u r = C h + v − 1 h − 1 个被淘汰掉。我们判断下c u r cur c u r 个串是否超出k k k :
若k > c u r k > cur k > c u r ,说明最高位放置'V',也没有将足够多的串给淘汰掉,因而我们接下来要继续在p o s + 1 pos+1 p os + 1 位放置'V'去淘汰剩余的c u r − k cur-k c u r − k 个串(该串此时只允许放h h h 个'H'、v − 1 v-1 v − 1 个'V')。 若k < c u r k<cur k < c u r ,说明淘汰过多,最高位应该放置'H',即淘汰不成功,考虑p o s + 1 pos+1 p os + 1 位放置'V'去淘汰剩余的k k k 个串(该串此时只允许放h − 1 h-1 h − 1 个'H'、v v v 个'V') 注意,我们可能要计算C 29 14 C^{14}_{29} C 29 14 ,先做乘法运算时会超过l o n g l o n g long\ long l o n g l o n g 范围,因此需要用递推式预先处理组合公式。
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 class Solution {public : string kthSmallestPath (vector<int >& destination, int k) { int v = destination[0 ], h = destination[1 ]; int comb[35 ][35 ] = {0 }; comb[0 ][0 ] = 1 ; for (int i = 1 ; i <= (v + h); i++){ comb[i][0 ] = comb[i][i] = 1 ; for (int j = 1 ; j < i; j++) comb[i][j] = comb[i - 1 ][j - 1 ] + comb[i - 1 ][j]; } string ans = "" ; int sum = 0 , posMax = (v + h); for (int pos = 1 ; pos <= posMax; pos++){ if (h >= 1 ){ int cur = comb[v + h - 1 ][h - 1 ]; if (k > cur) { k -= cur; v--; ans += "V" ; } else { h--; ans += "H" ; } } else { ans += "V" ; v--; } } return ans; } };