【2022-09-08】腾讯音乐秋招笔试三道编程题

恭喜发现宝藏!搜索公众号【TechGuide】回复公司名,解锁更多新鲜好文和互联网大厂的笔经面经,目前已更新至美团、微软…
作者@TechGuide【全网同名】
点赞再看,养成习惯,您动动手指对原创作者意义非凡🤝

第一题:

题目描述

给定一个只包含小写字母字符串,每次可以选择两个相同的字符删除,并在字符串结尾新增任意一个小写字母。
请问最少多少次操作后,所有的字母都不相同?

字符串长度<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个孩子。

你需要对每个结点赋值一个正整数,使得每个结点的左右子树权值和相等。

你需要返回所有结点的最小权值和对1e9+7取模的结果。

二叉树结点个数不超过1e5。

输入描述

{0,0,0}

输出描述

3

题目case如图:
在这里插入图片描述

思路

正常递归,因为两侧值相等,每次把左右子树小的值设置成大的值即可,然后本节点最小赋值为1。

不知道需不需要处理大数,反正Python不需要,其他语言可能需要注意一下long吧。

代码

Java版本
public int getTreeSum(TreeNode tree) {
     // write code here
     return (int) (traverse(tree) % ((Math.pow(10, 9) + 7)));
 }

 long traverse(TreeNode root) {
     if (root == null) return 0;
     long leftVal = traverse(root.left);
     long rightVal = traverse(root.right);
     return 1 + Math.max(leftVal, rightVal) * 2;
 }
 
}

class TreeNode {
 int val = 0;
 TreeNode left = null;
 TreeNode right = null;

 public TreeNode(int val) {
     this.val = val;
 }
}
// vx公众号关注TechGuide 实时题库 闪电速递
Python版本
class TechGuide:
    def getTreeSum(self, tree: TreeNode) -> int:
        def f(node):
            return 0 if not node else max(f(node.left), f(node.right)) * 2 + 1

        return f(tree) % 1000000007
# vx公众号关注TechGuide 实时题库 闪电速递
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值