阿里笔试

BM1 子集(最长递增子序列)

小强现在有n个物品,每个物品有两种属性xi和yi.他想要从中挑出尽可能多的物品满足以下条件:对于任意两个物品i和j,满足xi<xj且yi<yj或者xi>xj且yi>yj.问最多能挑出多少物品.

进阶:时间复杂度O(nlogn),空间复杂度O(n)

import java.util.*;

public class Main{
    public static int maxGoods(int[][] arr){
        // 将attribute进行转换并排序
        int n = arr.length;
        // 将二维数组按第一列升序排序,第一列相同则按第二列降序排序
        Arrays.sort(arr, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1,int[] o2){
                return o1[0] == o2[0] ? o2[1] - o1[1] : o1[0] - o2[0];
            }
        });
        // 记录arr[i][1]递增的最长序列
        // 取出第二列的元素,对其求最长递增子序列
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = arr[i][1];
        }
        //tails[k] 的值代表长度为k+1子序列 的尾部元素值
        int[] tails = new int[n];
        int res = 0;// res 为 tails当前长度
        for (int num : nums){
            int left = 0, right = res;//right为数组的长度,而不是length-1,这点要注意
            while(left < right){
                int mid = left + (right - left) / 2;
                if(tails[mid] < num) left = mid + 1;
                else right = mid;
            }
            tails[left] = num;
            if(right == res) res++;
        }
        return res;
    }

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int p = scanner.nextInt();
        for(int i = 0; i < p; i++){// p组数据
            int n = scanner.nextInt();// n件商品
            int[][] attribute = new int[n][2];// 属性
            for(int j = 0; j < 2; j++){
                for(int m = 0; m < n; m++){
                    attribute[m][j] = scanner.nextInt();
                }
            }
            // 处理操作
            int count = maxGoods(attribute);
            System.out.println(count);// 输出结果
        }
    }
}

BM2 小强爱数学

小强发现当已知xy=B以及x+y=A时,能很轻易的算出x^2+y^2的值.但小强想请你在已知A 和B的情况下,计算x^n+y^n出的值.因为这个结果可能很大,所以所有的运算都在模1e9+7下进行.

import java.util.*;
public class Main{
    public static final int CON = 1000000007;
    /*public static int math(int A, int B, int n){// 时间复杂度太高
        if(n == 0) return 2;
        if(n == 1) return A;
        return ((A * math(A, B, n - 1)) % CON - (B * math(A, B, n - 2) + CON) % CON);
    }*/
    // 采用备忘录求解
    public static long math(int A, int B, int n){
        long dp = 0;
        long dp0 = 2, dp1 = A;
        if(n == 0) return dp0;
        if(n == 1) return dp1;
        for (int i = 2; i <= n; i++) {
	  // 注意这里大数取余操作!!!
            dp = ((A * dp1) % CON - (B * dp0) % CON + CON) % CON;
            dp0 = dp1;
            dp1 = dp;
        }
        return dp;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        for(int i = 0; i < T; i++) {// T组数据
            int[] nums = new int[3];
            for (int j = 0; j < 3; j++) {
                nums[j] = scanner.nextInt();
            }
            System.out.println(math(nums[0], nums[1], nums[2]));
        }
    }
}

BM3 二叉树

小强现在有n个节点,他想请你帮他计算出有多少种不同的二叉树满足节点个数为n且树的高度不超过m的方案.因为答案很大,所以答案需要模上1e9+7后输出. 树的高度: 定义为所有叶子到根路径上节点个数的最大值. 例如: 当n=3,m=3时,有如下5种方案

import java.util.*;
public class Main{
    public static final int MOD = 1000000007;
    public  static long schemeNumber(int n, int high){
        // dp[i][j]表示i个节点最大深度为j的树数量
        long[][] dp = new long[n + 1][high + 1];
        Arrays.fill(dp[0], 1);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= high; j++) {
                for(int k = 0; k < i; k++) {
                    // 左子树节点数为k,右子树节点数为i-k-1,且左右子树都要求小于等于j-1
                    dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1] % MOD) % MOD;
                }
            }
        }
        return dp[n][high];
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        System.out.println(schemeNumber(n, m));
    }
}

BM4

import java.util.*;

public class Main {
    static int[] dx = {1, -1, 0, 0};
    static int[] dy = {0, 0, 1, -1};
    static int[][][] dp;
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();
        String[] tmp = line.split(" ");
        int m = Integer.parseInt(tmp[0]);
        int n = Integer.parseInt(tmp[1]);
        char[][] map = new char[m][n];
        int sx = 0, sy = 0, ex = 0, ey = 0;
        for (int i = 0; i < m; i++) {
            line = scanner.nextLine();
            for (int j = 0; j < n; j++) {
                char ch = line.charAt(j);
                map[i][j] = ch;
                if (ch == 'S') {
                    sx = i;
                    sy = j;
                }
                if (ch == 'E') {
                    ex = i;
                    ey = j;
                }
            }
        }
        
        bfs(map, sx, sy, ex, ey);
        for (int i = 0; i < 6; i++) {
            if (dp[ex][ey][i] != 0) {
                System.out.println(dp[ex][ey][i]);
                return;
            }
        }
        System.out.println(-1);
    }
    
    public static void bfs(char[][] map, int sx, int sy, int ex, int ey) {
        Deque<int[]> queue = new ArrayDeque<>();
        int m = map.length;
        int n = map[0].length;
        dp = new int[m][n][6];
        
        queue.offerFirst(new int[] {sx, sy, 0});
        while (!queue.isEmpty()) {
            int[] status = queue.pollLast();
            int x = status[0], y = status[1], t = status[2];
            int nx = 0, ny = 0, nt = 0;
            for (int i = 0; i < 5; i++) {
                if (i == 4) {
                    nx = m - 1 - x;
                    ny = n - 1 - y;
                    nt = t + 1;
                } else {
                    nx = x + dx[i];
                    ny = y + dy[i];
                    nt = t;
                }
                if (nx >= 0 && nx < m && ny >= 0 && ny < n && nt < 6 && map[nx][ny] != '#' && dp[nx][ny][nt] == 0) {
                    dp[nx][ny][nt] = dp[x][y][t] + 1;
                    if (nx == ex && ny == ey) {
                        return;
                    }
                    queue.offerFirst(new int[] {nx, ny, nt});
                }
            }
        }
    }
}

BM5 知识竞赛

最近部门要选两个员工去参加一个需要合作的知识竞赛,每个员工均有一个推理能力值Ai ,以及一个阅读能力值Bi 。如果选择第i个人和第j个人去参加竞赛,那么他们在阅读方面所表现出的能力为X=(Bi + Bj)/2,他们在推理方面所表现出的能力为Y=(Ai+Aj)/2。 现在需要最大化他们表现较差一方面的能力,即让min(X,Y)尽可能大,问这个值最大是多少。

进阶:时间复杂度O(nlogn),空间复杂度O(n)

import java.util.*;
public class Main{
    public static double maxDiff(int[][] arr, int n){
        Arrays.sort(arr,new Comparator<int[]>() {
            @Override
            public int compare(int[]o1,int[]o2) 
            {
                return Math.abs(o1[0] - o1[1]) - Math.abs(o2[0] - o2[1]);
            }
        });
        int maxX = arr[0][0];
        int maxY = arr[0][1];
        int maxMin = 0;
        for(int i = 1;i < n; i++){
             int current;
             if(arr[i][0] > arr[i][1])
                 current = arr[i][1] + maxY;
             else
                 current = arr[i][0] + maxX;
             if(current > maxMin)
                 maxMin = current;
             maxX = Math.max(arr[i][0], maxX);
             maxY = Math.max(arr[i][1], maxY);
        }
        double res = maxMin / 2.0;
        return res;
    }
    
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[][] arr = new int[n][2];
        for(int i = 0; i < n; i++){
            for(int j = 0; j < 2; j++){
                arr[i][j] = scanner.nextInt();
            }
        }
        System.out.println(maxDiff(arr, n));
    }
}

BM6 树上的最短链(图论/BFS) 经典!!!

在一个地区有n个城市以及n-1条无向边,每条边的时间边权都是1 ,并且这些城市是联通的,即这个地区形成了一个树状结构。每个城市有一个等级。 现在小强想从一个城市走到另一个不同的城市,并且每条边经过至多一次,同时他还有一个要求,起点和终点城市可以任意选择,但是等级必须是相同的。 但是小强不喜欢走特别远的道路,所以他想知道时间花费最小是多少。

进阶:时间复杂度O(n^2logn),空间复杂度O(n)

import java.util.*;
import java.math.*;
public class Main{
    // 深度优先搜索
    public static int BFS(int[] level, ArrayList<Integer>[] lists){
        int res = Integer.MAX_VALUE;
        int n = level.length;
        for(int i = 0;i < n; i++){// 对于每一个城市进行深度优先搜索
            Queue<Integer> queue = new LinkedList<>();
            boolean[] visit = new boolean[n];// 用于标记当前城市是否走过
            queue.offer(i);// 以城市i为起点
            visit[i] = true;
            int length = 0;// 记录走过的距离长度
            while(!queue.isEmpty()){
                int size = queue.size();
                int flag = 0;// 用于标记是否需要继续走,当走到与起点城市级别相等的其他城市时,就停止当前行进
                for(int j = 0; j < size; j++){
                    int temp = queue.poll();
                    if(temp != i && level[temp] == level[i]){// 到达相同级别其他城市
                        res = Math.min(res,length);// 记录最短距离
                        flag = 1;// 用于标记是否需要继续行进
                        break;
                    }
                    for(int x : lists[temp]){// 拜访其该城市连接的其他城市
                        if(!visit[x]){
                            queue.offer(x);
                            visit[x] = true;
                        }
                    }
                }
                if(flag == 1) break;
                length++;
            }
        }
        // 返回结果,若无满足要求答案,则返回-1
        return res == Integer.MAX_VALUE ? -1 : res;
    }


    public static void main(String []args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();// n个城市
        int[] level = new int[n];// 城市等级
        ArrayList<Integer>[] lists = new ArrayList[n];// n个链表,存储无向图
        for(int i = 0;i < n; i++){
            level[i] = scanner.nextInt();// 输入城市i级别
            lists[i] = new ArrayList<Integer>();// 创建城市i的连接链表
        }
        for(int i = 0;i < n-1; i++){// n - 1条无向边连接
            int x = scanner.nextInt()-1;// 城市标记为0 ~ n - 1,方便用下标索引
            int y = scanner.nextInt()-1;
            lists[x].add(y);// 相互连接两个城市
            lists[y].add(x);
        }
        int res = BFS(level, lists);
        System.out.println(res);
    }
}

BM7 牛牛们吃糖果(并查集+0-1背包问题)

有n个牛牛一起去朋友家吃糖果,第i个牛牛一定要吃ai块糖果. 而朋友家一共只有m块糖果,可能不会满足所有的牛牛都吃上糖果。 同时牛牛们有k个约定,每一个约定为一个牛牛的编号对(i,j),表示第i个和第j个牛牛是好朋友,他俩要么一起都吃到糖果,要么一起都不吃。 保证每个牛牛最多只出现在一个编号对中。 您可以安排让一些牛牛吃糖果,一些牛牛不吃。 要求使能吃上糖果的牛牛数量最多(吃掉的糖果总量要小于等于m),并要满足不违反牛牛们的k个约定。

import java.util.*;
// 并查集+0-1背包问题
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();// n 个牛牛
        int m = sc.nextInt();// m 颗糖果
        int[] a = new int[n];// 每个牛牛吃到的糖果 a[i]
        for (int i = 0; i < a.length; i++) {
            a[i] = sc.nextInt();
        }
        int[] v = new int[a.length];
        Arrays.fill(v, 1);
        int k = sc.nextInt();// k 个约定
        for (int i = 0; i < k; i++) {//第 i 个牛牛与第 j 个牛牛有约定 
            int x = sc.nextInt();
            int y = sc.nextInt();
            // 将有约定的牛牛绑定在一起
            a[x - 1] += a[y - 1];
            v[x - 1] += 1;
            v[y - 1] = 0;
        }
        // 用于记录m个糖果的最优分配结果
        int[] opt = new int[m + 1];
        Arrays.fill(opt, 0);
        for (int i = 0; i < n; i++) {
            if (v[i] == 0) {
                continue;
            }
            // 这一块有点疑惑???
            for (int j = m; j > a[i] - 1; --j) {
                opt[j] = Math.max(opt[j], (opt[j - a[i]] + v[i]));
            }
        }
        //最多能吃到糖果的牛牛个数
        System.out.print(opt[opt.length - 1]);
    }
}

BM8 方案数量

import java.util.Scanner;
public class Main {
    static int n, m;
    final static int mod = 10000;

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int T = s.nextInt();
        for (int times = 0; times < T; times++) {
            n = s.nextInt();
            m = s.nextInt();
            int[][] board = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    board[i][j] = s.nextInt();
                }
            }
            int ans = dpHandle(board);
            System.out.println(ans);
        }
    }

    private static int dpHandle(int[][] board) {
        int[][] dp = new int[n][m];
        dp[0][0] = 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int energy = board[i][j];
                //i:能够消耗的能量
                for (int useEnergy = 1; useEnergy <= energy; useEnergy++) {
                    //x消耗的能量
                    for (int xCost = 0; xCost <= useEnergy; xCost++) {
                        int nx = i, ny = j;
                        nx += xCost;
                        ny += useEnergy - xCost;
                        if (nx >= n || ny >= m) {
                            continue;
                        }
                        dp[nx][ny] = (dp[nx][ny] + dp[i][j]) % mod;
                    }
                }
            }
        }
        return dp[n - 1][m - 1];
    }
}

BM9

小强有一个长度为n的数组a和正整数m. 他想请你帮他计算数组a中有多少个连续子区间[l,r],其区间内存在某个元素出现的次数不小于次? 例如数组a=[1,2,1,2,3]且m=2,那么区间[1,3],[1,4],[1,5],[2,4],[2,5]都是满足条件的区间,但区间[3,4]等都是不满足条件的.

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int len = s.nextInt(), m = s.nextInt();
        int[] nums = new int[len];
        for (int i = 0; i < len; i++) {
            nums[i] = s.nextInt();
        }
        int left = 0;
        long ans = 0;
        Map<Integer, Integer> map = new HashMap<>();
        boolean find = false;
        for (int right = 0; right < len; right++) {
            int times = map.getOrDefault(nums[right], 0);
            times++;
            map.put(nums[right], times);
            if (times == m) {
                find = true;
            }
            while (find) {
                ans += len - right;
                int leftTimes = map.get(nums[left]);
                leftTimes--;
                map.put(nums[left], leftTimes);
                if (nums[left] == nums[right] && leftTimes < m) {
                    find = false;
                }
                left++;
            }
        }
        System.out.println(ans);
    }
}

BM10

小强有两个序列a和b,这两个序列都是由相同的无重复数字集合组成的,现在小强想把a序列变成b序列,他只能进行以下的操作: 从序列a中选择第一个或者最后一个数字并把它插入a中的任意位置。 问小强至少需要几次操作可以将序列a变为序列b。

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = cin.nextInt();
        }
        Map<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            map.put(cin.nextInt(),i);
        }
        // 将序列表示成b的下标
        for (int i = 0; i < n; i++) {
            a[i] = map.get(a[i]);
        }
        // 求下标最长连续上升序列
        int max = 1;
        int cur = 1;
        // 从第二个开始计算
        for (int i = 1; i < a.length; i++) {
            if(a[i]>a[i-1]) {
                cur++;
                max = Math.max(max,cur);
            }else {
                cur = 1;
            }
        }
        System.out.println(n-max);
    }
}
全部评论
点赞 回复 分享
发布于 03-17 11:18 北京

相关推荐

SinyWu:七院电话面的时候问我有没有女朋友,一听异地说你赶紧分。我:???
点赞 评论 收藏
分享
1 1 评论
分享
牛客网
牛客企业服务