第一题:
题目描述
给定一个只包含小写字母字符串,每次可以选择两个相同的字符删除,并在字符串结尾新增任意一个小写字母。
请问最少多少次操作后,所有的字母都不相同?
字符串长度<1e3
输入描述
abab
输出描述
2
解释:
第一次把2个a变成f,第二次把2个b变成b。得到fb,每个字母都不相同,最少操作次数为2。
思路
贪心就行了,每次把选2个字母变成当前出现次数最少的字母。因为字符串长度就1000,最多进行999次操作,每次操作遍历所有字母找出现次数最小的就可以。总体复杂度O(26n)
顺便做个follow-up,如果把字符串长度拉到1e5呢?其实可以以O(n)的解法来解。先考虑会消除多少次,对于某个字母出现m次,那么这个字母要操作m/2次使其变成0、1,同时产出m/2个字符,我们先把这产出的放到一边不考虑,先遍历所有字母,查看会产出多少字符。
得到产出字符数之后,可以遍历剩余的字母,根据上面所述,一个字母最终会剩下0/1,如果一个字母剩下0个,说明操作途中其他产出的字母就可以放到这个位置,不需要额外操作。否则产出的字符仍然需要额外操作。
考虑ay每个字母都出现3次,z不出现。一共可以产出25个字母(ay每个产出1个),同时a~y剩余1个,z剩余0个。那么因为有一个剩余0个的,前面在任意字母操作的时候,就可以直接往z这里放一个。这样还剩下24个产出,这产出的字母,每一个字母都需要额外操作一次,所以拢共需要操作24+25=49次。
代码
Java版本
class TechGuide {
public int minOperations(String str) {
// write code here
char[] arr = str.toCharArray();
int[] map = new int[128];
int n = arr.length;
int count = 26;
for (int i = 0; i < n; i++) {
if (map[arr[i] - 'a'] == 0) {
count--;
}
map[arr[i] - 'a']++;
}
int res = 0;
for (int i = 'a'; i <= 'z'; i++) {
if (map[i - 'a'] >= 2) {
while (count > 0 && map[i - 'a'] > 2) {
map[i - 'a'] -= 2;
count--;
res++;
}
}
}
if (count > 0) {
for (int i = 0; i < 128; i++) {
res += (map[i]) / 2;
}
} else {
for (int i = 0; i < 128; i++) {
if (map[i] != 0) {
res += map[i] - 1;
}
}
}
return res;
}
// vx公众号关注TechGuide 实时题库 闪电速递
Python版本
class TechGuide:
def minOperations(self, str: str) -> int:
c = [0] \* 26
for i in str: c[ord(i) - ord('a')] += 1
ans = 0
more = 0
for i in range(26):
ans += c[i] // 2
more += c[i] // 2
c[i] %= 2
for i in range(26):
if c[i] == 0 and more:
c[i] += 1
more -= 1
ans += more
return ans
# vx公众号关注TechGuide 实时题库 闪电速递
第二题:
题目描述
已知一个二叉树的先序遍历序列和中序遍历序列,但其中一些节点的值可能相同。
请你返回所有满足条件的二叉树。二叉树在数组中的顺序是任意的。
输入描述
[1,1,2],[1,2,1]
输出描述
[{1,1,#,#,2},{1,#,1,2}]
case中会产出以下2个树:、
思路
经典递归。只需要枚举在中序遍历序列中每个可能成为下一个根节点的节点即可。因为是枚举的中序序列,那么假设某一个节点为根节点,这个节点左侧所有节点均为它的左子树,递归处理即可。
代码
Java版本
public ArrayList<TreeNode> getBinaryTrees(ArrayList<Integer> preOrder, ArrayList<Integer> inOrder) {
// write code here
return buildTree(preOrder, 0, preOrder.size() - 1,
inOrder, 0, inOrder.size() - 1);
}
ArrayList<TreeNode> buildTree(ArrayList<Integer> preOrder, int preStart, int preEnd,
ArrayList<Integer> inOrder, int inStart, int inEnd) {
ArrayList<TreeNode> res = new ArrayList<>();
if (preStart > preEnd || inStart > inEnd) {
res.add(null);
return res;
}
int rootVal = preOrder.get(preStart);
ArrayList<Integer> indexs = new ArrayList<>();
for (int i = inStart; i <= inEnd; i++) {
if (inOrder.get(i) == rootVal) {
indexs.add(i);
}
}
for (Integer index : indexs) {
ArrayList<TreeNode> lefts = buildTree(preOrder, preStart + 1, preStart + index - inStart,
inOrder, inStart, index - 1);
ArrayList<TreeNode> rights = buildTree(preOrder, preStart + index - inStart + 1, preEnd,
inOrder, index + 1, inEnd);
for (TreeNode left : lefts) {
for (TreeNode right : rights) {
TreeNode root = new TreeNode(rootVal);
root.left = left;
root.right = right;
res.add(root);
}
}
}
return res;
}
// vx公众号关注TechGuide 实时题库 闪电速递
Python版本
class TechGuide:
def getBinaryTrees(self, preOrder: List[int], inOrder: List[int]) -> List[TreeNode]:
if not preOrder: return [None]
ans = []
n = len(preOrder)
for i in range(n):
if inOrder[i] == preOrder[0]:
for l in self.getBinaryTrees(preOrder[1:i + 1], inOrder[:i]):
for r in self.getBinaryTrees(preOrder[i + 1:], inOrder[i + 1:]):
node = TreeNode(preOrder[0])
node.left = l
node.right = r
ans.append(node)
return ans
# vx公众号关注TechGuide 实时题库 闪电速递
第三题:
题目描述
给定一棵二叉树,二叉树的每个结点只有0或2个孩子。
你需要对每个结点赋值一个正整数,使得每个结点的左右子树权值和相等。