牛客阿里笔试练习

Posted qq_40707462

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客阿里笔试练习相关的知识,希望对你有一定的参考价值。

【2021】阿里巴巴编程题(4星)

https://www.nowcoder.com/test/30440638/summary

1、二维最长上升子序列

小强现在有n个物品,每个物品有两种属性Xi和Yi,他想要从中挑出尽可能多的物品满足以下条件:对于任意两个物品,满足 X 和 Y 同升同降


问最多能挑出多少物品。

思路:

  1. 先将所有物品按x升序排列,随后在无序的y中取一个最长上升子序列即可。

  2. 需要注意的是,在排序过程中,对于相同大小的x,需要将大的y排在前边,因为排在后边,因为x不递增,会导致错误的结果。例如(1,2) (1,3) (1,4),这一组中最长子序列长度正确应为1,但将小y排在前边,所有的 y序列 会算出3的错误结果。

参考300、最长上升子序列【中等】,有动态规划和二分两种解法

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class Main 
    //用于x,y同时排序
    public static class XY implements Comparable
        public int x;
        public int y;
        public XY(int x,int y)
                this.x=x;
                this.y=y;
        
        //将所有物品按【x】【升序】排列,x相同按【y】【降序】
        public int compareTo(Object o)
            XY tmp=(XY) o;
            if (this.x > tmp.x) return 1;
            else if (this.x < tmp.x) return -1;
            else 
                //x相同,y大的放前边
                if (this.y > tmp.y) return -1;
                else if (this.y < tmp.y)return 1;
                return 0;
            
        
    
    public static void main(String[] args) 
        //最长上升子序列的变种,需要保证xy的同升同降,
        // 即先将所有物品按【x】升序排列,随后在无序的【y】中取一个最长上升子序列即可
        Scanner sc = new Scanner(System.in);
        int totalnum = sc.nextInt();//共几组数
        for (int k = 0; k < totalnum; k++)
            int len = sc.nextInt();//每组数几个数字
            int[]nums1=new int[len];
            int[]nums2=new int[len];
            for (int i = 0; i <len; i++) nums1[i]=sc.nextInt();
            for (int i = 0; i <len; i++) nums2[i]=sc.nextInt();
            XY[]xy=new XY[len];
            for(int i=0;i<len;i++) xy[i]=new XY(nums1[i],nums2[i]);
            Arrays.sort(xy);
            int res=help(xy);
            System.out.println(res);
        
    

    //最长上升子序列 二分
    public static int help(XY[] nums) 
        int len=nums.length;
        if(len<2) return len;
        List<Integer> list=new ArrayList<>();
        list.add(nums[0].y);
        for(int i=1;i<len;i++)
            if (nums[i].y>list.get(list.size()-1))//1、nums[i]>list中的最大数
                list.add(nums[i].y);//直接加在list后面
                continue;
            
            //2、二分查找插入位置,用nums[i]覆盖掉【比nums[i]大的元素中】最小的那个
            int l=0,r=list.size();
            while(l<r)
                int mid=(l+r)/2;
                if(list.get(mid)<nums[i].y) l=mid+1;
                else r=mid;
            
            list.set(l,nums[i].y);
        
        return list.size();
    

2、n次方

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


输入例子1:
                3
                4 4 3
                2 3 4
                5 2 6
输出例子1:
                16
                999999993
                9009

思路:
num[1]=x+y
num[2]=x2+y2=(x+y)2-2xy=a2-2b
num[3]=x3+y3=(x+y)(x2+y2)-xy(x+y)=num[1] * num[2] -b * num[1]
num[n]=a * num[n-1] -b * num[n-2]


public class Main 
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        //T表示有T组数据
        int T = sc.nextInt();
        for (int i = 1; i <= T; i++) 
            //n表示有n个物品
            int A = sc.nextInt();
            int B = sc.nextInt();
            int n = sc.nextInt();
            long result = helper(A, B, n);
            System.out.println(result);

        
    

    private static long helper(int a, int b, int n) 
        if (n == 0) return 2;
        if (n == 1) return a;
        // 未优化
        long[] dp = new long[n + 1];//dp[i]表示x的第i次方+y的第i次方的和
        dp[0] = 2;
        dp[1] = a;
        double mod = 1e9 + 7;
        for (int i = 2; i < dp.length; i++) 
            dp[i] = (long)(((a * dp[i - 1] % (mod)) - (b * dp[i - 2] % (mod)) + mod) % (mod));
        
        return dp[n];
    

优化空间

import java.util.Scanner;

public class Main 
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        //T表示有T组数据
        int T = sc.nextInt();
        for (int i = 1; i <= T; i++) 
            //n表示有n个物品
            int A = sc.nextInt();
            int B = sc.nextInt();
            int n = sc.nextInt();
            long result = helper(A, B, n);
            System.out.println(result);

        
    

    private static long helper(int a, int b, int n) 
        if (n == 0) return 2;
        if (n == 1) return a;
        // 优化,因为每次求结果,只与前一次和前前一次的结果有关
        // 所以dp只需保存长度为3的数组即可。
        long[] dp1 = new long[3];
        dp1[1] = 2;
        dp1[2] = a;
        double mod = 1e9 + 7;
        for (int i = 2; i <= n; i++) 
            dp1[0] = dp1[1];
            dp1[1] = dp1[2];
            dp1[2] = (long)(((a * dp1[1] % (mod)) - (b * dp1[0] % (mod)) + mod) % (mod));
        

        return dp1[2];
    

3、不同的二叉树的个数

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

思路:动态规划,参考96、不同的二叉搜索树【中等】
注意:dp要用long!!!

import java.util.Scanner;
import java.util.Arrays;
public class Main
    public static void main(String[] args) 
        int kmod= (int) (1e9+7);
        Scanner in = new Scanner(System.in);
        int n=in.nextInt();
        int m=in.nextInt();
        //dp[n][m] 总数为n 高度最大为m
        long[][]dp=new long[n+1][m+1];
        Arrays.fill(dp[0], 1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=0;k<i;k++)//总共i,左边k,中间1,右边i-k-1
                    dp[i][j] += dp[k][j-1]*dp[i-k-1][j-1]%kmod;
                    dp[i][j] %=kmod;
                
            
        
        System.out.println(dp[n][m]);
    

4、对称飞行器(三维bfs)
三维广度搜索+位运算优化时间和空间
飞行器有次数限制。所以(x,y)点的状态应该再加一个维度:飞行次数z。P(x,y,z1)和Q(x,y,z2)是两种不同的状态。

假设z1<z2,即P和Q在相同的横纵坐标,但是P剩余的飞行次数更多。假设从(x,y,z2)走到终点的最优解是n步,从(x,y,z1)一定可以走n步到达终点。此时P状态走到最优点的步数更少。所以在层次遍历的最优解中不该包含z2.

也就是说在向z增加转移的过程中,我们应该看matrix[x][y][0]…matrix[x][y][z]中是否已经有为1的点,如果有就不必再在第z层再走x,y。

我们可以用位运算压缩三维数组,matrix[x][y]第z位代表是否已经遍历过(x,y,z)点。至于判断该点是否可走,我们应该看当前位置(x,y)小于等于z的位是否有1。类似于子网掩码的算法。高于z为置0,低位置1,与matrix[x][y]相与。得到结果大于0则说明有1不需遍历。等于0说明使用更少的飞行器没有走过这一点。可以加入遍历集。

以上是关于牛客阿里笔试练习的主要内容,如果未能解决你的问题,请参考以下文章

小红的375(思维+数学)

数据结构数组相关代码(数据结构笔试复测Leecode牛客)

牛客练习赛91 ABCD题解

python3 牛客网:OJ在线编程常见输入输出练习(ACM模式)

牛客练习赛91 ABCD题解

牛客练习赛87 E.贪吃蛇(构造矩阵快速幂)