牛客阿里笔试练习
Posted qq_40707462
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客阿里笔试练习相关的知识,希望对你有一定的参考价值。
【2021】阿里巴巴编程题(4星)
https://www.nowcoder.com/test/30440638/summary
1、二维最长上升子序列
小强现在有n个物品,每个物品有两种属性Xi和Yi,他想要从中挑出尽可能多的物品满足以下条件:对于任意两个物品,满足 X 和 Y 同升同降
问最多能挑出多少物品。
思路:
-
先将所有物品按x升序排列,随后在无序的y中取一个最长上升子序列即可。
-
需要注意的是,在排序过程中,对于相同大小的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说明使用更少的飞行器没有走过这一点。可以加入遍历集。
以上是关于牛客阿里笔试练习的主要内容,如果未能解决你的问题,请参考以下文章