2022.9.25 用友 笔试
之前选修过会计双学位,了解到用友这个公司,笔试投一下体验一下难度。
整体感觉 比较水。应该是 没系统学过算法的也能做出来的那种程度。
整体包括单选+多选+2编程+1编程题
1、纯暴力的
题目:一些数字 1-n,n的范围很小(1~52),先找到1,把1去掉,随后 找下一个除4余2的,除4余3的,除4余0的,除4余1的,直到最后一个
很明显数据量才50,暴力就可以的。实际实现的时候有个小优化,提前把 数字模4的结果存起来,作为info数组。为了防止手动构造一个队列,用一个valid数组,表示数字是否被选过
如果选过,那以后就不要选择这个数字。
数据量很少,最后直接暴力过一下,哪个还没有被标记,就是答案。
package yongyou.t01; import java.util.HashMap; import java.util.List; import java.util.Scanner; class Main{ public static int shrinkCircle (int[] circle) { // write code here int n = circle.length; int[] info = new int[n]; boolean[] valid = new boolean[n]; for(int i = 0; i < n; i++){ info[i] = circle[i] % 4; } int index = 0; while (circle[index] != 1){ index++; } valid[index] = true; int num = 1; //go int c = 2; while(num != n-1){ if(!valid[index] && info[index] == c){ //find! valid[index] = true; c = c == 3 ? 0 : c+1; num++; //System.out.println("num++, num="+num); } index = index == n-1 ? 0 : index+1; } //ans for(int i = 0; i < n; i++){ if(!valid[i]){ return circle[i]; } } return -1; } public static void main(String[] args) { int[] a = new int[]{9,8,7,6,5,4,3,2,1}; System.out.println(shrinkCircle(a)); // Scanner in = new Scanner(System.in); } }
2、
在一个三维直角坐标系中,有一只蚂蚁从原点 (0, 0, 0) 开始,向目标点 (l, m, n) 前进,蚂蚁的前进规则如下: 1、l, m, n >= 0,且 l + m + n > 0; 2、蚂蚁每次只能沿X/Y/Z轴的方向前进一个单位,比如,当前蚂蚁在点(x0, y0, z0),下一步只能前进到下面三个点中的任意一个:(x0 + 1, y0, z0),或(x0, y0 + 1, z0),或(x0, y0, z0 + 1)。 返回所有可以从原点 (0, 0, 0) 到目标点 (l, m, n) 的可行路径数量。 * @param x int整型 目标点的X坐标 * @param y int整型 目标点的Y坐标 * @param z int整型 目标点的Z坐标 * @return long长整型 */说实话这个是高中数学题,我们可以认为,有三个商品abc,每一个又有多个,问你有多少种组合方式。相当于
1、在所有的 a+b+c 中,先选出a个位置 放a,个数为C(a+b+c, a) [不太会打上下的格式,就是排列组合中的 C,不是A]
2、在剩下的b+c个中,选出b个放b
3、c的话剩余的位置,只有1种
答案就是 第一步结果 * 第二部结果 * 1
【高中数学题,就比如从(0,0) 岛 (2,3) 有多少条路,相当于要在总共5步里面,选2个往上走,剩下自动向右了,答案就是 C(5, 2)】
注意说返回的long,应该很大,我再计算过程中用的Big Integer, 其它语言的可以看看有没有各自的函数。
有个优化点,我没有实现,就是计算C的时候,为了防止溢出,可以计算分子 、分母的过程中,同时除以他俩的最大公约数,比如 5*4*3 / 3*2*1,在分子是5*4时,分母3*2,他俩可以同时除以gcd(20, 6) = 2, 变成分子10, 分母3。
class Main { public static long countPaths (int x, int y, int z) { // write code here int all = x + y + z; BigInteger b1 = process(all, x); BigInteger b2 = process(all - x, y); return b1.multiply(b2).longValue(); } public static BigInteger process(int a, int b){ //总共a个 选出b 有多少种 BigInteger top = BigInteger.valueOf(1), down = BigInteger.valueOf(1); int time= b; for(int i = 0; i < time; i++){ top = top.multiply(BigInteger.valueOf(a)); down = down.multiply(BigInteger.valueOf(b)); a--;b--; } return top.divide(down); } public static void main(String[] args) { System.out.println(countPaths(1,0,0)); Scanner in = new Scanner(System.in); }
优化点:使用info数组,info[i] 表示,最长递增子序列长度必须是 i+1的时候,最后一个数字最小是什么。比如2 3 5 这个子序列,应该 info[2] = 5,表示长度为3的子序列,最后一个最小 时 5。
对于任何一个数字,通过二分查找加速,o(nlogn ) 最优解肯定能过。暴力的方式不清楚能不能过。
package yongyou.t03; import java.util.Arrays; import java.util.Scanner; class Main { public static int lengthOfList (int[] nums) { // write code here //最长递增子序列 //必须以 info[i] i+1长度的递增子序列,最后一个数字 最小是什么 int n = nums.length; int[] info = new int[n]; if(n <= 1){ return n; } int ans = 0; info[0] = nums[0]; for(int i = 1; i < n; i++){ int cur = nums[i]; //二分 找到 >= 最左的位置 int left = 0, right = ans; int curAns = -1; while(left <= right){ int mid = left + (right - left)/2; if(info[mid ] >= cur){ curAns = mid; right = mid - 1; }else{ left = mid + 1; } } if(curAns == -1){ ++ans; info[ans] = cur; }else{ info[curAns] = Math.min(info[curAns], cur); } } System.out.println(Arrays.toString(info)); return ans+1; } public static void main(String[] args) { System.out.println(lengthOfList(new int[]{10,9,2,5,3,7,101,18})); Scanner in = new Scanner(System.in); } }