蚂蚁集团暑期实习笔试-3.23

第一题:输入两个长度相同且全由小写字符组成的字符串,遍历两个字符串,如果当前位置的两个字符相同,将他们转换为大写;如果不同这保留,最后输出变换之后的字符串。

/**
 * @Author: ShuWang Li
 * @Date: 2025/3/19 11:06
 * @Description: 字符串的变换
 **/
public class Solution {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        String s1 = in.next();
        String s2 = in.next();

        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < n; i++){
            char c1 = s1.charAt(i);
            char c2 = s2.charAt(i);
            if(c1 == c2){
                sb.append(Character.toUpperCase(c1));
            }else{
                sb.append((char)Math.max(c1, c2));
            }
        }
        System.out.println(sb.toString());
        in.close();
    }
}

第二题:
第一行输入 n-1 个由 0和1组成的数字字符串,第二行输出有1到n之间的数字组成的序列,如果第一行下标为i的位置的数字为0的话,第二行输出下标为i + 1的数字应该就比下标为i的数字小,如果第一行下标为1的位置数字为1,第二行下标为i+1的数字就比i位置的数字大。以下是例子:

0101
3 2 4 1 5

答案:

/**
 * @Author: ShuWang Li
 * @Date: 2025/3/24 11:46
 * @Description: 根据当前位置的值与上一个位置大小关系构建数组
 **/
public class SequenceRearrangement {
    public static int[] rearrangeSequence(String s) {
        // n 是序列的长度,由输入的字符串 s 的长度加 1 得到
        int n = s.length() + 1;

        // 创建一个长度为 n 的数组 seq,存储从 1 到 n 的数字
        int[] seq = new int[n];
        for (int i = 0; i < n; i++) {
            seq[i] = i + 1;  // 初始化 seq 数组为 [1, 2, 3, ..., n]
        }

        // 使用栈来帮助我们根据条件调整数字顺序
        Stack<Integer> stack = new Stack<>();

        // 结果数组,用来存放最终排列好的数字
        int[] result = new int[n];
        int index = 0;  // 用于在结果数组中插入元素的索引

        // 遍历字符串 s 的每一位,检查相邻数字之间的大小关系
        for (int i = 0; i < n - 1; i++) {
            stack.push(seq[i]);  // 将当前数字 seq[i] 压入栈

            // 如果当前字符是 '1',表示当前数字 seq[i] 要小于下一个数字 seq[i+1]
            // 此时我们将栈中的数字按逆序输出,因为 seq[i+1] 必须比 seq[i] 大
            if (s.charAt(i) == '1') {
                // 将栈中的元素逆序弹出并放入结果数组,形成一个递增的顺序
                while (!stack.isEmpty()) {
                    result[index++] = stack.pop();  // 将栈中的元素逆序添加到结果中
                }
            }
        }

        // 最后,将最后一个数字 seq[n-1] 压入栈
        stack.push(seq[n - 1]);

        // 最后,弹出栈中的所有元素(确保按照从大到小的顺序处理)
        while (!stack.isEmpty()) {
            result[index++] = stack.pop();  // 将栈中的元素逆序放入结果数组
        }

        // 返回最终排列好的数字序列
        return result;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int[] result = rearrangeSequence(s);

        // 打印结果
        for (int num : result) {
            System.out.print(num + " ");
        }
    }
}

第三题:
第一行输入一个整数 n 代表接下来输入的数字的个数,第二行输入n个数字,其中x和y可以这些数字当中的两个,其中x和y的位置为这些数字,并且x要在y的左边,找出满足|x - y| = |x| - |y|的个数。例如

输入:
6
1 1 4 5 1 4
输出:
7

解法1:暴力求解: 时间复杂度O(n^2)

public class SequenceRearrangement {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = scanner.nextInt();
        }
        System.out.println(countValidPairs(nums));
    }

    public static int countValidPairs(int[] nums) {
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                int x = nums[i], y = nums[j];
                if(x * y > 0 && Math.abs(x) >= Math.abs((y)) || y == 0) {
                    count++;
                }
            }
        }
        return count;
    }
}

解法2:分治法+树状dp:时间复杂度O(nlogn)

/**
 * @Author: ShuWang Li
 * @Date: 2025/3/24 11:46
 * @Description: 具体来说,给定一个数组,我们需要找到所有满足以下条件的对 (i, j)(其中 i < j):
 * 1. |a[i] - a[j]| = |a[i]| - |a[j]|
 *
 * 该程序通过将数字分为正数、负数和零三类来优化匹配过程,减少了暴力匹配的计算量。
 */
public class SequenceRearrangement {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 输入数组的大小
        int n = sc.nextInt();
        int[] nums = new int[n];

        // 输入n个整数
        for (int i = 0; i < n; i++) {
            nums[i] = sc.nextInt();
        }

        // 用来存储正数、负数和零
        List<Integer> pos = new ArrayList<>();  // 正数列表
        List<Integer> neg = new ArrayList<>();  // 负数列表
        int zeroCount = 0;  // 零的个数

        // 遍历数组,按正负零分类
        for (int num : nums) {
            if (num > 0) {
                pos.add(num);  // 如果是正数,加入正数列表
            } else if (num < 0) {
                neg.add(num);  // 如果是负数,加入负数列表
            } else {
                zeroCount++;  // 如果是零,零的数量加一
            }
        }

        // 计算正数对的数量
        int countPos = countPairs(pos.stream().mapToInt(i -> i).toArray());

        // 计算负数对的数量(将负数转换为正数进行处理)
        int[] negAbs = neg.stream().mapToInt(i -> Math.abs(i)).toArray();
        int countNeg = countPairs(negAbs);

        // 计算零的对数,零的组合数是 C(zeroCount, 2)
        int countZero = zeroCount * (zeroCount - 1) / 2;

        // 总的满足条件的对数
        int total = countPos + countNeg + countZero;
        System.out.println(total);  // 输出结果
    }

    /**
     * 计算一个数组中满足条件的对 (i, j) 的数量,其中 i < j
     * 具体做法:通过二叉索引树(Fenwick Tree)来高效统计每个数字的出现次数
     */
    private static int countPairs(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }

        // 使用TreeSet去重,确保每个数字在计算时只考虑一次
        TreeSet<Integer> unique = new TreeSet<>();
        for (int num : nums) {
            unique.add(num);
        }

        // 将去重后的数字排序,并为每个数字生成一个排名
        List<Integer> sorted = new ArrayList<>(unique);
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < sorted.size(); i++) {
            map.put(sorted.get(i), i + 1);  // 映射每个数字到它在排序数组中的位置
        }

        // 创建一个Fenwick Tree来统计排名
        FenwickTree ft = new FenwickTree(sorted.size());
        int count = 0;

        // 从右到左遍历数组,统计每个数字的出现次数
        for (int i = nums.length - 1; i >= 0; i--) {
            int num = nums[i];
            int rank = map.get(num);  // 获取当前数字的排名
            count += ft.query(rank);  // 查询当前数字排名之前出现的数字对的数量
            ft.update(rank, 1);  // 更新Fenwick Tree,表示当前数字出现过一次
        }

        return count;  // 返回满足条件的对的数量
    }

    /**
     * Fenwick Tree(也叫Binary Indexed Tree)的实现,用于高效的前缀和查询和更新。
     * 这里用于统计数字出现的次数。
     */
    static class FenwickTree {
        int size;
        int[] tree;

        public FenwickTree(int size) {
            this.size = size;
            tree = new int[size + 1];  // 初始化Fenwick Tree数组
        }

        // 更新树状数组(更新索引为index的元素的值)
        public void update(int index, int delta) {
            while (index <= size) {
                tree[index] += delta;  // 增加delta值
                index += index & -index;  // 移动到父节点
            }
        }

        // 查询前缀和(查询从1到index的和)
        public int query(int index) {
            int sum = 0;
            while (index > 0) {
                sum += tree[index];  // 累加当前节点的值
                index -= index & -index;  // 移动到父节点
            }
            return sum;
        }
    }
}
### 蚂蚁集团笔试相关内容 #### 笔试题型与解析 蚂蚁集团笔试通常涉及算法设计、数据结构应用以及编程能力评估。例如,在2025年的春季招聘中,有一道关于字符串处理的题目,输入字符串为 `"Ab01!?. +_*/"`(其中第八个字符为空格)。此题考察的是字符串匹配和模式识别的能力[^1]。 另一类典型问题是区间覆盖问题。具体来说,给定`n`个格子和`m`种操作,目标是最少使用多少次操作来完全覆盖所有格子。这类问题的核心在于贪心算法的应用——通过优先选择能够覆盖最多未染色区域的操作逐步解决问题[^3]。 以下是基于上述区间的解决方案实现: ```python def min_operations_to_paint(n, m, operations): intervals = [] for op in operations: l_i, r_i = op intervals.append((l_i, r_i)) # 按照右端点排序 intervals.sort(key=lambda x: x[1]) count = 0 last_covered = 0 selected_ops = [] for interval in intervals: if interval[0] > last_covered: break if interval[1] >= last_covered: selected_ops.append(interval) last_covered = interval[1] count += 1 if last_covered < n: return -1 result_indices = [operations.index(op)+1 for op in selected_ops] return (count, result_indices) # 示例调用 n = 10 m = 4 operations = [(1, 4), (2, 7), (3, 8), (6, 9)] result = min_operations_to_paint(n, m, operations) print(result) # 输出应为(2, [2, 3]) 表示最少两次操作即可完成全部染色 ``` #### 复习建议与经验分享 对于准备参加蚂蚁集团笔试的同学而言,除了掌握基础的数据结构外,还需要熟悉常见的算法模板及其变体形式。比如动态规划、图论中的最短路径计算等都是高频考点[^2]。此外,多参与模拟练习并总结错题也是提升成绩的有效途径之一。 #### 总结 综上所述,蚂蚁集团笔试试题涵盖了广泛的计算机科学基础知识,并注重实际应用场景下的灵活运用能力测评。考生需具备扎实理论功底的同时也要善于解决复杂工程实践难题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值