原题目地址: 牛客10道练习题1
发现有问题, 请提出来. 谢谢啦!
class Exam1 {
/**
* 1、求解连续数列
* <p>
* 已知连续正整数数列{K}=K1,K2,K3...Ki的各个数相加之和为S,i=N (0<S<100000, 0<N<100000), 求此数列K。
* 对连续理解错了, 这里的连续是限制d=1. 所以才会出现下面这代码, 这代码原本的意思是解所有的和等于Sn的前N项. 包含d=1的.
* @param s
*/
public static void t1(String s) {
int[] split = Arrays.stream(s.split("\\s+")).mapToInt(Integer::parseInt).toArray();
// 数列和
int Sn = split[0];
// 项数目
int n = split[1];
if (!Utils.isBetweenAnd(Sn, 0, 100000) || !Utils.isBetweenAnd(n, 0, 100000)) {
System.out.println("-1");
return;
}
// 公差d, 默认从0开始
Double d = 0.0;
// a1的最大值
Double a1 = getA1(d, Sn, n);
if (a1.intValue() != a1) {
a1 = Math.floor(a1);
d = getD(a1, Sn, n);
}
boolean flag = false;
while (a1 > 0) {
if (d.intValue() == d && d == 1) {
// System.out.println("a1: " + a1.intValue() + "\td:" + d.intValue());
// d = getD(--a1, Sn, n);
// continue;
flag = true;
break;
} else {
a1--;
}
d = getD(a1, Sn, n);
}
if (!flag) {
System.out.println("-1");
return;
}
String result = "";
for (int i = 0; i < n; i++) {
result += (int) (a1 + i * d) + " ";
}
System.out.println(result);
}
/**
* 根据公差d 求首项
*
* @param d 公差
* @return 首项
*/
private static double getA1(double d, double Sn, double n) {
return Sn / n - (n - 1) * d / 2;
}
/**
* 根据首项求公差d
*
* @param a1 首项
* @return 首项
*/
private static double getD(double a1, double Sn, double n) {
return 2 * (Sn / n - a1) / (n - 1);
}
/**
* 2、查找众数及中位数
* <p>
* 众数是指一组数据中出现次数量多的那个数,众数可以是多个
* <p>
* 中位数是指把一组数据从小到大排列,最中间的那个数,如果这组数据的个数是奇数,那最中间那个就是中位数,如果这组数据的个数为偶数,那就把中间的两个数之和除以2,所得的结果就是中位数
* <p>
* 查找整型数组中元素的众数并组成一个新的数组,求新数组的中位数
* 输入描述:
* <p>
* 输入一个一维整型数组,数组大小取值范围 0<N<1000,数组中每个元素取值范围 0<E<1000
* <p>
* 输出描述:
* <p>
* 输出众数组成的新数组的中位数
*
* @param s
*/
public static void t2(String s) {
List<Integer> nums = Arrays.stream(s.split("\\s+")).map(Integer::parseInt).collect(Collectors.toList());
int len = nums.size();
if (len == 0 || len > 1000) {
System.err.println("invalid input");
return;
}
Collections.sort(nums);
if (nums.get(len - 1) > 1000 || nums.get(len - 1) <= 0) {
System.err.println("invalid input");
return;
}
// 分组
Map<Integer, Long> collect = nums.stream().collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));
// 找到数目最大的值
int max = Math.toIntExact(collect.values().stream().max(Long::compareTo).get());
// 求众数数组
List<Integer> mode = new ArrayList<>();
collect.forEach((key, value) -> {
if (value == max) {
mode.add(key);
}
});
// 众数数组排序
Collections.sort(mode);
// 求中位数
if (mode.size() % 2 == 1) {
System.out.println(mode.get((mode.size() + 1) >> 2));
} else {
Double value = (mode.get(mode.size() >> 2) + mode.get(mode.size() >> 2 - 1)) / 2.0;
if (value.intValue() == value) {
System.out.println(value.intValue());
} else {
System.out.println(value);
}
}
}
/**
* 3、寻找相同子串
* <p>
* 给你两个字符串 t 和 p ,要求从 t 中找到一个和 p 相同的连续子串,并输出该字串第一个字符的下标。
*
* @param t
* @param p
*/
public static void t3(@NotNull String t, @NotNull String p) {
// Scanner scanner = new Scanner(System.in);
// String t = scanner.nextLine();
// String p = scanner.nextLine();
if (t.length() < p.length() || t.length() > 1000000 || p.length() > 10000) {
System.err.println("invalid input");
return;
}
if ("".equals(t) || "".equals(p)) {
System.out.println("No");
return;
}
int i = t.indexOf(p);
if (i > -1) {
System.out.println(i + 1);
} else {
System.out.println("No");
}
}
/**
* 4、字符串统计
* <p>
* 给定两个字符集合,一个为全量字符集,一个为已占用字符集。已占用的字符集中的字符不能再使用,要求输出剩余可用字符集。
* <p>
* <p>
* <p>
* 输入描述:
* <p>
* 1、输入为一个字符串,一定包含@符号。@前的为全量字符集,@后的字为已占用字符集。
* <p>
* 2、已占用字符集中的字符一定是全量字符集中的字符。字符集中的字符跟字符之间使用英文逗号分隔。
* <p>
* 3、每个字符都表示为字符加数字的形式,用英文冒号分隔,比如a:1,表示1个a字符。
* <p>
* 4、字符只考虑英文字母,区分大小写,数字只考虑正整形,数量不超过100。
* <p>
* 5、如果一个字符都没被占用,@标识仍然存在,例如a:3,b:5,c:2@
* <p>
* 输出描述:
* <p>
* 输出可用字符集,不同的输出字符集之间回车换行。
* <p>
* 注意,输出的字符顺序要跟输入一致。不能输出b:3,a:2,c:2
* <p>
* 如果某个字符已全被占用,不需要再输出。
*/
public static void t4(@NotNull String s) {
// Scanner scanner= new Scanner(System.in);
// String s = scanner.nextLine();
if (s.length() == 0) {
System.err.println("invalid input");
return;
}
String[] split = s.split("@");
if (split.length != 2) {
System.err.println("invalid input");
return;
}
String[] tempArray;
// all
LinkedMap<String, Integer> all = new LinkedMap<>();
tempArray = split[0].split(",");
for (int i = 0; i < tempArray.length; i++) {
String[] map = tempArray[i].split(":");
all.put(map[0], Integer.parseInt(map[1]));
}
// used
LinkedMap<String, Integer> used = new LinkedMap<>();
tempArray = split[1].split(",");
for (int i = 0; i < tempArray.length; i++) {
String[] map = tempArray[i].split(":");
used.put(map[0], Integer.parseInt(map[1]));
}
used.forEach((k, v) -> {
int V = all.get(k) - v;
if (V > 0) {
all.put(k, all.get(k) - v);
} else {
all.remove(k);
}
});
StringBuilder sb = new StringBuilder();
all.forEach((k, v) -> {
sb.append(k).append(":").append(v).append(",");
});
System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
}
/**
* 5、磁盘容量排序
* <p>
* 磁盘的容量单位常用的有M,G,T这三个等级,它们之间的换算关系为1T = 1024G,1G = 1024M,现在给定n块磁盘的容量,请对它们按从小到大的顺序进行稳定排序,例如给定5块盘的容量,1T,20M,3G,10G6T,3M12G9M排序后的结果为20M,3G,3M12G9M,1T,10G6T。注意单位可以重复出现,上述3M12G9M表示的容量即为3M+12G+9M,和12M12G相等。
* <p>
* <p>
* <p>
* 输入描述:
* <p>
* 输入第一行包含一个整数n(2 <= n <= 100),表示磁盘的个数,接下的n行,每行一个字符串(长度大于2,小于30),表示磁盘的容量,由一个或多个格式为mv的子串组成,其中m表示容量大小,v表示容量单位,例如20M,1T,30G,10G6T,3M12G9M。
* <p>
* <p>
* <p>
* 磁盘容量m的范围为1到1024的正整数,容量单位v的范围只包含题目中提到的M,G,T三种,换算关系如题目描述。
* <p>
* 输出描述:
* <p>
* 输出n行,表示n块磁盘容量排序后的结果。
**/
public static void t5() {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
if (n > 100 || n < 2) {
System.err.println("invalid input");
return;
}
String[] disks = new String[n];
// 对应位置的磁盘容量
int[] diskCapacity = new int[n];
String diskStrTemp;
for (int i = 0; i < n; i++) {
diskStrTemp = scanner.next();
if (diskStrTemp.length() < 2 || diskStrTemp.length() > 30) {
System.err.println("invalid input");
return;
}
disks[i] = diskStrTemp;
diskCapacity[i] = Utils.conversionDiskCapacityToM(diskStrTemp);
}
int diskCapacityTemp = 0;
// 插入排序
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j > 0; j--) {
// 小于的时候才交换, 否则直接break掉该次循环
if (diskCapacity[i] > diskCapacity[j]) {
diskCapacityTemp = diskCapacity[i];
diskCapacity[i] = diskCapacity[j];
diskCapacity[j] = diskCapacityTemp;
diskStrTemp = disks[i];
disks[i] = disks[j];
disks[j] = diskStrTemp;
} else {
break;
}
}
}
Arrays.stream(disks).forEach(System.out::println);
}
/**
* 6、太阳能板最大面积
* <p>
* 给航天器一侧加装长方形或正方形的太阳能板(图中的红色斜线区域),需要先安装两个支柱(图中的黑色竖条),再在支柱的中间部分固定太阳能板。但航天器不同位置的支柱长度不同,太阳能板的安装面积受限于最短一侧的那根支柱长度。如图:
* <p>
* 现提供一组整形数组的支柱高度数据,假设每根支柱间距离相等为1个单位长度,计算如何选择两根支柱可以使太阳能板的面积最大。
* <p>
* <p>
* <p>
* 输入描述:
* <p>
* 10,9,8,7,6,5,4,3,2,1
* <p>
* 注:支柱至少有2根,最多10000根,能支持的高度范围1~10^9的整数。柱子的高度是无序的,例子中递减只是巧合。
*
* @param s
*/
public static void t6(@NotNull String s) {
// 柱子
int[] pillars = Arrays.stream(s.split(",")).mapToInt(Integer::parseInt).toArray();
// 柱子间的容量数组长度
int len = pillars.length - 1;
// 柱子间的容量数组
int[] pillarsLoad = new int[len];
// 填充容量数组
for (int i = 0; i < len; i++) {
pillarsLoad[i] = Math.min(pillars[i], pillars[i + 1]);
}
int max = 0, temp, minPillarsLoad = pillarsLoad[0];
// 第一个容量的位置
for (int i = 0; i < len - 1; i++) {
// 默认第一个是最小容量
minPillarsLoad = pillarsLoad[i];
// 末尾容量的位置, 从第一个柱子旁边移动到最后.
for (int j = i + 1; j < len; j++) {
// 求最小容量
minPillarsLoad = Math.min(minPillarsLoad, pillarsLoad[j]);
// 求当前的max
temp = minPillarsLoad * (j - i + 1);
max = Math.max(temp, max);
}
}
// out
System.out.println(max);
}
/**
* 7、靠谱的车
* <p>
* 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。
* <p>
* <p>
* <p>
* 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。
* <p>
* <p>
* <p>
* 比如:
* <p>
* 1. 23再多一块钱就变为25;
* <p>
* 2. 39再多一块钱变为50;
* <p>
* 3. 399再多一块钱变为500;
* <p>
* 小明识破了司机的伎俩,准备利用自己的学识打败司机的阴谋。
* <p>
* 给出计费表的表面读数,返回实际产生的费用。
* <p>
* 思路 -> 每九个数进1, 那么把对应的数字转成九进制数字, 在计算其对应的十进制即可; 可以参考numberMap映射
*/
/**
* @param n 伪九进制
*/
public static void t7(int n) {
if (n < 1 || n > 888888888) {
System.err.println("invalid input");
return;
}
// Map<Character, Integer> numberMap = new HashMap<Character, Integer>() {{
// put('0', 0);
// put('1', 1);
// put('2', 2);
// put('3', 3);
// put('5', 4);
// put('6', 5);
// put('7', 6);
// put('8', 7);
// put('9', 8);
// }};
String N = n + "";
int result = 0, m = 1;
char temp;
for (int i = N.length() - 1; i >= 0; i--) {
temp = N.charAt(i);
if (temp < '4') {
result += (temp - 48) * m;
} else
result += (temp - 49) * m;
m *= 9;
}
System.out.println(result);
}
/**
* 8、整数对最小和
* <p>
* 给定两个整数数组array1、array2,数组元素按升序排列。假设从array1、array2中分别取出一个元素可构成一对元素,现在需要取出k对元素,并对取出的所有元素求和,计算和的最小值
* <p>
* 注意:两对元素如果对应于array1、array2中的两个下标均相同,则视为同一对元素。
*/
public static void t8(int[] arr1, int[] arr2, int k) {
int len1 = arr1.length;
int len2 = arr2.length;
if (k > len1 * len2) {
System.err.println("error");
return;
}
int result = 0;
int[] sums = new int[arr1.length * arr2.length];
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
sums[j + i * arr2.length] = arr1[i] + arr2[j];
}
}
Arrays.sort(sums);
while (k > 0) {
result += sums[--k];
}
/**
* i:0 1 1 0
* + 2 2 3 3
* j:0 0 1 1
*/
System.out.println(result);
}
/**
* 9、判断字符串子序列
* <p>
* 给定字符串 target和 source, 判断 target 是否为 source 的子序列。
* <p>
* 你可以认为 target 和 source 中仅包含英文小写字母。字符串 source可能会很长(长度 ~= 500,000),而 target 是个短字符串(长度 <=100)。
* <p>
* 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"abc"是"aebycd"的一个子序列,而"ayb"不是)。
*
* @param target 短字符串
* @param source 长字符串
*/
public static void t9(String target, String source) {
int len1 = target.length();
int len2 = source.length();
if (len1 > 100 || len2 > 500000) {
System.err.println("error");
return;
}
int i = len1 - 1;
int j = len2 - 1;
I:
for (; i >= 0; i--) {
for (; j >= 0; j--) {
if (target.charAt(i) == source.charAt(j)) {
if (i == 0)
break I;
j--;
break;
}
}
}
System.out.println(j);
}
/**
* 10、按身高和体重排队
* <p>
* 某学校举行运动会,学生们按编号(1、2、3…n)进行标识,现需要按照身高由低到高排列,对身高相同的人,按体重由轻到重排列;对于身高体重都相同的人,维持原有的编号顺序关系。请输出排列后的学生编号。
* <p>
* <p>
* <p>
* 输入描述:
* <p>
* 两个序列,每个序列由n个正整数组成(0 < n <= 100)。第一个序列中的数值代表身高,第二个序列中的数值代表体重。
* <p>
* 输出描述:
* <p>
* 排列结果,每个数值都是原始序列中的学生编号,编号从1开始
*
* @param n 几个人
* @param heights 身高数组
* @param wrights 体重数组
*/
public static void t10() {
Scanner sc = new Scanner(System.in);
int len = sc.nextInt();
while (sc.hasNextInt()) {
int[] heights = new int[len];
int[] weights = new int[len];
for (int i = 0; i < len; i++) {
heights[i] = sc.nextInt();
}
for (int i = 0; i < len; i++) {
weights[i] = sc.nextInt();
}
int[] code = new int[len];
for (int i = 0; i < len; i++) {
code[i] = i + 1;
}
int temp;
// 身高: 低到高
// 体重: 轻到重
for (int i = 1; i < len; i++) {
temp = heights[i];
for (int j = i; j > 0; j--) {
if (heights[j - 1] > heights[j]) {
swap(heights, j, j - 1);
swap(weights, j, j - 1);
swap(code, j, j - 1);
} else if (heights[j - 1] == heights[j]) {
// 身高相等, 比较体重
if (weights[j - 1] > weights[j]) {
swap(weights, j, j - 1);
swap(code, j, j - 1);
}
}
}
}
for (int i = 0; i < len; i++) {
System.out.print(heights[i] + " " + code[i] + " ");
}
break;
}
}
Utils.java
class Utils{
/**
* @param num
* @param lower 下界
* @param upper 上界
* @return boolean
*/
protected static boolean isBetweenAnd(int num, int lower, int upper) {
if (lower < num && num < upper) {
return true;
}
return false;
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 将容量数据实体化, 转换为int数字, 单位是M.
*
* @param diskCapacity 容量数据
* @return
*/
protected static int conversionDiskCapacityToM(@NotNull String diskCapacity) {
int len = diskCapacity.length();
if (len == 0) {
return 0;
}
Set<Character> characters = diskCapacityMap.keySet();
int result = 0;
Character temp;
int o = 0;
for (int i = 0; i < len; i++) {
temp = diskCapacity.charAt(i);
if (characters.contains(temp)) {
result += Integer.parseInt(diskCapacity.substring(o, i)) * diskCapacityMap.get(temp);
o = i + 1;
}
}
return result;
}
}
测试demo
// Exam1.t1("525 6");
Exam1.t2("10 11 21 19 21 17 21 16 21 18 15");
Exam1.t2("2 1 5 4 3 3 9 2 7 4 6 2 15 4 2 4");
Exam1.t2("5 1 5 3 5 2 5 5 7 6 7 3 7 11 7 55 7 9 98 9 17 9 15 9 9 1 39 ");
Exam1.t2("1 8 0 7 7 7 7 6 6 6 6 1 1 1 5 5 5 5");
// Exam1.t3("AVERDXIVYERDIAN", "AN ");
// Exam1.t4("a:3,b:5,c:2@a:1,b:2");
// Exam1.t5();
// Exam1.t6("10,1,8,7,6,5,5,5,5,5");
// Exam1.t7(5);
// Exam1.t7(888888888);
// Exam1.t8(new int[]{1, 1, 2}, new int[]{1, 2, 3},6);
// Exam1.t9("ccc", "abcccc");
// Exam1.t10();
不想输入, 有的地方就没用Scanner. 如果发现有问题, 请及时跟我说
(第八题复杂度高了,我有空优化。)
大家互相进步啊~