java - 算法 - 腾讯2018春招
1.小Q定义了一种数列称为翻转数列:
给定整数n和m, 满足n能被2m整除。对于一串连续递增整数数列1, 2, 3, 4..., 每隔m个符号翻转一次, 最初符号为'-';。
例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
小Q现在希望你能帮他算算前n项和为多少。
输入描述:
输入包括两个整数n和m(2 <= n <= 109, 1 <= m), 并且满足n能被2m整除。
输出描述:
输出一个整数, 表示前n项和。
输入例子1:
8 2
输出例子1:
8
package tx; import java.math.BigInteger; import java.util.*; public class q1{ public static void main(String[] args){ Scanner s = new Scanner(System.in); String str = s.nextLine(); String[] strArr = str.split(" "); BigInteger n = new BigInteger(strArr[0]); BigInteger m = new BigInteger(strArr[1]); BigInteger sum = m.multiply(n).divide(new BigInteger("2")); System.out.println(sum); } }
题本身不难- - 用初中数学只是就能得出结果是 m*n/2
主要是用到了bigInteger处理大数字。
2.
牛牛和羊羊正在玩一个纸牌游戏。这个游戏一共有n张纸牌, 第i张纸牌上写着数字ai。
牛牛和羊羊轮流抽牌, 牛牛先抽, 每次抽牌他们可以从纸牌堆中任意选择一张抽出, 直到纸牌被抽完。
他们的得分等于他们抽到的纸牌数字总和。
现在假设牛牛和羊羊都采用最优策略, 请你计算出游戏结束后牛牛得分减去羊羊得分等于多少。
输入描述:
输入包括两行。
第一行包括一个正整数n(1 <= n <= 105),表示纸牌的数量。
第二行包括n个正整数ai(1 <= ai <= 109),表示每张纸牌上的数字。
输出描述:
输出一个整数, 表示游戏结束后牛牛得分减去羊羊得分等于多少。
输入例子1:
3 2 7 4
输出例子1:
5
package tx; import java.util.*; public class q2{ public static void main(String[] args){ Scanner s = new Scanner(System.in); String str1 = s.nextLine(); int num = Integer.parseInt(str1); String str2 = s.nextLine(); String[] strArr = str2.split(" "); int[] iArr = new int[num]; for(int i = 0; i < num; i++) { iArr[i] = Integer.parseInt(strArr[i]); } sort(iArr, 0, num - 1); int sum = 0; for(int i = 0; i < num; i++){ if(i % 2 == 0){ sum = sum + iArr[i]; } else{ sum = sum - iArr[i]; } //System.out.println(iArr[i]); } System.out.println(sum); } public static void sort( int[] iArr, int start, int end){ //冒泡排序会超时,采用快速排序 if(start > end){ return; } int base = start; int low = start; int high = end; while(low < high){ while(low < end && iArr[low] >= iArr[base]){ low++; } while(high > start && iArr[high] <= iArr[base]){ high--; } if(low > high){ break; } else{ int temp = iArr[high]; iArr[high] = iArr[low]; iArr[low] = temp; } } int temp = iArr[high]; iArr[high] = iArr[base]; iArr[base] = temp; sort(iArr, start, high - 1); sort(iArr, high + 1, end); } }
考察了排序,先排序后遍历做加减法就行。
而且由于有运行时间限制,所以用快速排序,冒泡排序等时间复杂度是O²的会超时。
3.小Q的父母要出差N天,走之前给小Q留下了M块巧克力。小Q决定每天吃的巧克力数量不少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有巧克力吃,请问他第一天最多能吃多少块巧克力
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,表示父母出差的天数N(N<=50000)和巧克力的数量M(N<=M<=100000)。
输出描述:
输出一个数表示小Q第一天最多能吃多少块巧克力。
输入例子1:
3 7
输出例子1:
4
package tx; import java.util.*; public class q3{ public static void main(String[] args){ Scanner s = new Scanner(System.in); int n = s.nextInt(); //天数 int m = s.nextInt(); //巧克力数量 //二分法查找第一天的最大巧克力数量 int start = 0; int end = m; while(start < end){ int sweetNum = (end + start) / 2; if(isEnough(n, m, sweetNum)){ //System.out.println(sweetNum + "够了"); start = sweetNum + 1; } else{ end = sweetNum; } } if(n == 1) { //n = 1时二分查找会有问题,所以单独拿出来。 System.out.println(m); } else { System.out.println(end - 1); } } public static boolean isEnough(int n , int m, int sweetNum){ //判断 sweet在n天内能否够吃 for(int i = 0; i < n ; i++) { m = m - sweetNum; sweetNum = (int)Math.ceil(sweetNum * 1.0 / 2); } if(m >= 0){ return true; } else{ return false; } } }
本质:从m个顺序排列的数字中(1 - m)寻找符合要求的最大值。
用遍历会超时,用二分查找,寻找符合要求的最大值。
4.小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000)。
接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数量Y(Y<=100)。保证A不等于B。
输出描述:
输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。
输入例子1:
5 2 3 3 3
输出例子1:
9
package tx; import java.math.BigInteger; import java.util.*; public class q4{ public static void main(String[] args){ Scanner s = new Scanner(System.in); int k = Integer.parseInt(s.nextLine()); //天数 String str = s.nextLine(); //巧克力数量 String[] steArr = str.split(" "); int a = Integer.parseInt(steArr[0]); //长度 int x = Integer.parseInt(steArr[1]); //数量 int b = Integer.parseInt(steArr[2]); int y = Integer.parseInt(steArr[3]); //求出两种歌的个数有多少种组合。 ArrayList<Integer> aa = new ArrayList(); ArrayList<Integer> bb = new ArrayList(); for(int i = 0; i <= x; i++){ int r = k - a * i; if(r % b == 0 && r/b <= y){ aa.add(i); bb.add(r/b); } } BigInteger bi = new BigInteger("0"); for(int i = 0; i < aa.size(); i++){ BigInteger temp = getC(aa.get(i), x); temp = temp.multiply(getC(bb.get(i), y)); bi = bi.add(temp); } bi = bi.mod(new BigInteger("1000000007")); System.out.println(bi); } public static BigInteger getC(int x, int y){ if (x == 0) { return new BigInteger("1"); } BigInteger bi = new BigInteger("1"); for(int i = 1; i <= y; i++){ bi = bi.multiply(new BigInteger("" + i)); } for(int i = 1; i <= x; i++){ bi = bi.divide(new BigInteger("" + i)); } for(int i = 1; i <= ( y - x); i++){ bi = bi.divide(new BigInteger("" + i)); } bi = bi.mod(new BigInteger("1000000007")); return bi; } }
我是先求出x 和 y的数量上的组合种类,然后对每种情况分别求x和y的 C(n,m)的乘积, 然后结果相加
比如例题中只有一种情况:x取1个,y取1个
c(1,3) * c(1,3) = 9
x从3个中取1个,y也是从3个中取1个,总共有9中不同取法。
c(n,m) : 不考虑顺序的情况下,从m个物品中抽出n个有多少种排列组合
数学公式:C(n,m)=n! / ( m! * (n-m)! )
还有2个- -明天再做。。。