1.【爱奇艺】考虑定义在两正整数上的函数SSR(平方根之和的平方):SSR(A, B) = (sqrt(A) + sqrt(B))^2。牛牛对函数值为整数的情况很感兴趣。现在给定整数n和m,请帮助牛牛计算有序对(A, B)的数量, 满足1 ≤ A ≤ n, 1 ≤ B ≤ m而且SSR(A, B)是一个整数。
思路:
因为SSR(A, B) = (sqrt(A) + sqrt(B))^2 = A + B + 2sqrt(AB),所以只需要判断sqrt(AB)是否为整数即可。
可以发现,当 A = i ,B = i * j * j时,进行开方运算后结果一定为整数。
例如,从小的值开始遍历,当A = 1时, 可以取1*1*1, 1*2*2, 1*3*3,…直到<= B值
当A = 2时, 可以取2*1*1, 2*2*2, 2*3*3 … 直到 <= B值
解答:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();
int n = scanner.nextInt();
int big = m > n ? m : n;
int small = m < n ? m : n;
int res = 0;
for (int i = 1; i <= small; i++) {
int s = 1;
for (int j = 2; j <= i / j; j++) {
if (i % (j * j) == 0) {
s = j * j;
}
}
int r = i / s;
for (int j = 1; j * j * r <= big; j++) {
res++;
}
}
System.out.println(res);
}
}
2.【爱奇艺】对于任意两个正整数x和k,我们定义repeat(x, k)为将x重复写k次形成的数,例如repeat(1234, 3) = 123412341234,repeat(20,2) = 2020.牛牛现在给出4个整数x1, k1, x2, k2, 其中v1 = (x1, k1), v2 = (x2, k2),请你来比较v1和v2的大小。
例如:1010 1 10101010 2。
思路:
按照给定的值进行数据的拼接,判断两个数哪个的长度长,长度长的数据较大;若数据长度相同,则需要逐个字符进行比较。
解答:
import java.util.Scanner;
public class aqy1 {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int x1 = sc.nextInt();
int k1 = sc.nextInt();
int x2 = sc.nextInt();
int k2 = sc.nextInt();
compare(x1, k1, x2, k2);
}
public static void compare(int x1, int k1, int x2, int k2) {
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
while (k1-- > 0) sb1.append(x1 + "");
while (k2-- > 0) sb2.append(x2 + "");
int l1 = sb1.length(), l2 = sb2.length();
if (l1 > l2) {
System.out.println("Greater");
return;
} else if (l1 < l2) {
System.out.println("Less");
return;
}
for (int i = 0; i < l1; ++i)
if (sb1.charAt(i) > sb2.charAt(i)) {
System.out.println("Greater");
return;
} else if (sb1.charAt(i) < sb2.charAt(i)) {
System.out.println("Less");
return;
}
System.out.println("Equal");
}
}
3.【爱奇艺】一个合法的括号匹配序列有以下定义:
1、空串""是一个合法的括号匹配序列
2、如果"X"和"Y"都是合法的括号匹配序列,"XY"也是一个合法的括号匹配序列
3、如果"X"是一个合法的括号匹配序列,那么"(X)"也是一个合法的括号匹配序列
4、每个合法的括号序列都可以由以上规则生成。
例如: "","()","()()","((()))"都是合法的括号序列
对于一个合法的括号序列我们又有以下定义它的深度:
1、空串""的深度是0
2、如果字符串"X"的深度是x,字符串"Y"的深度是y,那么字符串"XY"的深度为max(x,y) 3、如果"X"的深度是x,那么字符串"(X)"的深度是x+1
例如: "()()()"的深度是1,"((()))"的深度是3。牛牛现在给你一个合法的括号序列,需要你计算出其深度。
思路:
左右括号的题一般用栈都很好做,遇到左括号就放到栈里,遇到右括号就pop出一个左括号(因为肯定合法,不需要什么判断)。这道题其实就是问栈里边最多的时候有多少个左括号。由于没有别的要进行处理的,甚至可以用一个 int 来当做栈,记录栈里边有多少左括号。
解答:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
int cnt = 0, max = 0, i;
for (i=0; i<s.length(); ++i) {
if (s.charAt(i) == '(')
cnt++;
else
cnt--;
max = Math.max(max, cnt);
}
System.out.println(max);
}
}
4.【爱奇艺】【数字游戏】牛牛举办了一场数字游戏,有n个玩家参加这个游戏,游戏开始每个玩家选定一个数,然后将这个数写在纸上(十进制数,无前缀零),然后接下来对于每一个数字将其数位按照非递减顺序排列,得到新的数,新数的前缀零将被忽略。得到最大数字的玩家赢得这个游戏。例如:2 6301 1940 输出结果为:1036
思路:
首先要将输入的每个数字的数位按照非递减顺序排列,然后将所有的数字进行排序
解答:
// 我是写个方法用List做的反转,然后用StringBuffer直接在后面加,再返回为int的反转值【Integer.parseInt()会自动去掉前缀0】
// 接着 主方法写个取最大的反转值就行
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int max = 0;
while (num-- > 0) {
int cur = getReverse(sc.nextInt());
max = cur > max ? cur : max;
}
System.out.println(max);
}
static int getReverse(int x) {
List<Integer> temp = new ArrayList<Integer>();
while (x != 0) {
temp.add(x%10);
x /= 10;
}
Collections.sort(temp);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < temp.size(); i++) {
sb.append(temp.get(i));
}
return Integer.parseInt(sb.toString());
}
}
5.【爱奇艺】【缺失的括号】一个完整的括号字符串定义规则如下:
1、空字符串是完整的。
2、如果s是完整的字符串,那么(s)也是完整的。
3、如果s和t是完整的字符串,将它们连接起来形成的st也是完整的。
例如,"(()())", ""和"(())()"是完整的括号字符串,"())(", "()(" 和 ")"是不完整的括号字符串。
牛牛有一个括号字符串s,现在需要在其中任意位置尽量少地添加括号,将其转化为一个完整的括号字符串。请问牛牛至少需要添加多少个括号。
思路:
一个左括号需要对应一个右括号,需要注意的点是,字符串最开始如果有右括号的话,需要单独计数。
解答:
public static void main(String args[]){
Scanner in = new Scanner(System.in);
String str = in.nextLine();
//count计数多出来的"(",n计数字符串最前面的")"
int count = 0, n=0;
for(int i = 0; i < str.length(); i++){
if(str.charAt(i) == '('){
count++;
}
if(str.charAt(i) == ')') {
if(count == 0){
n++;
}else{
count--;
}
}
}
System.out.println(count+n);
}
}
6.【vivo】小v所在的公司即将举行年会,年会方案设计过程中必不可少的一项就是抽奖活动。小v在本次活动中被委以重任,负责抽奖活动的策划;为了让中奖的礼物更加精美且富有神秘感,打算采用礼品盒来包装奖品,此时小v发挥了自己的创意想捉弄一下获奖的同事,便采取了多重包装来包装奖品。
现给出一个字符串,并假定用一对圆括号( )表示一个礼品盒,0表示奖品,你能据此帮获奖者算出最少要拆多少个礼品盒才能拿到奖品吗?
输入:(()(()((()(0))))) 输出:5
输入:(((0))) 输出:3
实现思路:一对圆括号()代表一个礼品盒,若左括号和右括号之间没有0则代表该礼品盒为空则不需要拆开
实现算法:
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = br.readLine();
int output = solution(inputStr );
System.out.println(output);
}
private static int solution(String str) {
// TODO Write your code here
char[] arr = str.toCharArray();
int count = 0;
for(int i = 0; i < arr.length; i++){
if(arr[i] == '('){
count++;
}else if(arr[i] == ')'){
count--;
}else if(arr[i] == '0'){
return count;
}
}
return 0;
}
}
7.【vivo】
小v在vivo手机的应用商店中下载了一款名为“一维消消乐”的游戏,介绍如下:
1、给出一些不同颜色的豆子,豆子的颜色用数字(0-9)表示,即不同的数字表示不同的颜色;
2、通过不断地按行消除相同颜色且连续的豆子来积分,直到所有的豆子都消掉为止;
3、假如每一轮可以消除相同颜色的连续 k 个豆子(k >= 1),这样一轮之后小v将得到 k*k 个积分;
4、由于仅可按行消除,不可跨行或按列消除,因此谓之“一维消消乐”。
请你帮助小v计算出最终能获得的最大积分。
示例: 输入:1 4 2 2 3 3 2 4 1 输出:21
示例说明: 第一轮消除3,获得4分,序列变成1 4 2 2 2 4 1
第二轮消除2,获得9分,序列变成1 4 4 1
第三轮消除4,获得4分,序列变成1 1
第四轮消除1,获得4分,序列为空
总共得分21分
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = br.readLine();
int input[] = parseInts(inputStr.split(" "));
int output = solution(input);
System.out.println(output);
}
private static int[] parseInts(String[] strArr) {
if (strArr == null || strArr.length == 0) {
return new int[0];
}
int[] intArr = new int[strArr.length];
for (int i = 0; i < intArr.length; i++) {
intArr[i] = Integer.parseInt(strArr[i]);
}
return intArr;
}
private static int solution(int[] input) {
// TODO Write your code here
if(input == null || input.length == 0){
return 0;
}
int len = input.length;
return DFS(input, len);
}
public static int DFS(int[] arr, int len){
if(len == 1){
return 1;
}
if(len == 2){
if(arr[0] == arr[1]){
return 4;
}else{
return 2;
}
}
int max = 0;
int L = 0;
for(int i = 1; i < len; i++){
if(arr[i] != arr[L]){
int[] copy = new int[len - (i - L)];
int j = 0;
for(; j < L; j++){
copy[j] = arr[j];
}
for(int r = i; r < len; r++){
copy[j++] = arr[r];
}
max = Math.max(max, DFS(copy, copy.length) + (i - L)*(i - L));
L = i;
}
}
if(L == 0){
return len * len;
}
int[] copy = new int[L];
for(int j = 0; j < L; j++){
copy[j] = arr[j];
}
max = Math.max(max, DFS(copy, copy.length) + (len - L) * (len - L));
return max;
}
}
8.【vivo】小v是公司的运维工程师,现有一个有关应用程序部署的任务如下:
1、一台服务器的磁盘空间、内存是固定的,现在有N个应用程序要部署;
2、每个应用程序所需要的磁盘、内存不同,每个应用程序允许访问的用户数也不同,且同一个应用程序不能在一台服务器上部署多个。
对于一台服务器而言,如何组合部署应用程序能够使得单台服务器允许访问的用户数最多?
输入描述:
输入包括三个参数,空格分隔,分别表示服务器的磁盘大小、内存大小,以及应用程序列表;
其中第三个参数即应用程序列表,表述方式为:多个应用程序信息之间用 '#' 分隔,每个应用程序的信息包括 ',' 分隔的部署所需磁盘空间、内存、允许访问的用户量三个数字;比如 50,20,2000 表示部署该应用程序需要50G磁盘空间,20G内存,允许访问的用户数是2000
输出描述:
单台服务器能承载的最大用户数
输入例子1:
15 10 5,1,1000#2,3,3000#5,2,15000#10,4,16000 =>磁盘大小15G,内存大小10G,应用程序列表(5,1,1000)、(2,3,3000)、(5,2,15000)、(10,4,16000)
输出例子1:
31000
例子说明1:
组合部署服务5,2,15000、10,4,16000 ,可以让单台服务器承载最大用户数31000
解题思路:该问题为背包问题
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = br.readLine();
String[] input = inputStr.split(" ");
int totalDisk = Integer.parseInt(input[0]);
int totalMemory = Integer.parseInt(input[1]);
List<Service> services = parseServices(input[2].split("#"));
int output = solution(totalDisk, totalMemory, services);
System.out.println(output);
}
private static int solution(int totalDisk, int totalMemory, List<Service> services) {
// TODO Write your code here
int len = services.size();
int[][][] dp = new int[len + 1][totalDisk + 1][totalMemory + 1];
for(int i = 1; i <= len; i++)
for(int j = totalDisk; j > 0; j--)
for(int k = totalMemory; k > 0; k--){
if(j >= services.get(i - 1).getDisk() && k >= services.get(i - 1).getMemory()){
dp[i][j][k] = Math.max(dp[i - 1][j][k],
dp[i - 1][j - services.get(i - 1).getDisk()][k - services.get(i - 1).getMemory()]
+ services.get(i - 1).getusers());
}else{
dp[i][j][k] = dp[i - 1][j][k];
}
}
return dp[len][totalDisk][totalMemory];
}
private static List<Service> parseServices(String[] strArr) {
if (strArr == null || strArr.length == 0) {
return new ArrayList<Service>(0);
}
List<Service> services = new ArrayList<>(strArr.length);
for (int i = 0; i < strArr.length; i++) {
String[] serviceArr = strArr[i].split(",");
int disk = Integer.parseInt(serviceArr[0]);
int memory = Integer.parseInt(serviceArr[1]);
int users = Integer.parseInt(serviceArr[2]);
services.add(new Service(disk, memory, users));
}
return services;
}
static class Service {
private int disk;
private int memory;
private int users;
public Service(int disk, int memory, int users) {
this.disk = disk;
this.memory = memory;
this.users = users;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
public int getMemory() {
return memory;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getusers() {
return users;
}
public void setusers(int users) {
this.users = users;
}
}
}
9.【字节跳动】万万没想到之聪明的编辑
我叫王大锤,是一家出版社的编辑。我负责校对投稿来的英文稿件,这份工作非常烦人,因为每天都要去修正无数的拼写错误。但是,优秀的人总能在平凡的工作中发现真理。我发现一个发现拼写错误的捷径:
1>三个同样的字母连在一起,一定是拼写错误,去掉一个的就好啦:比如 helllo -> hello
2>两对一样的字母(AABB型)连在一起,一定是拼写错误,去掉第二对的一个字母就好啦:比如 helloo -> hello
3>上面的规则优先“从左到右”匹配,即如果是AABBCC,虽然AABB和BBCC都是错误拼写,应该优先考虑修复AABB,结果为AABCC
我特喵是个天才!我在蓝翔学过挖掘机和程序设计,按照这个原理写了一个自动校对器,工作效率从此起飞。用不了多久,我就会出任CEO,当上董事长,迎娶白富美,走上人生巅峰,想想都有点小激动呢!
……
万万没想到,我被开除了,临走时老板对我说: “做人做事要兢兢业业、勤勤恳恳、本本分分,人要是行,干一行行一行。一行行行行行;要是不行,干一行不行一行,一行不行行行不行。” 我现在整个人红红火火恍恍惚惚的……
请听题:请实现大锤的自动校对程序
输入描述:
第一行包括一个数字N,表示本次用例包括多少个待校验的字符串。
后面跟随N行,每行为一个待校验的字符串。
输出描述:
N行,每行包括一个被修复后的字符串。
输入例子1:
2
helloo
wooooooow
输出例子1:
hello
woow
解题思路:
利用正则表达式进行匹配
(.)\\1+ => (.)代表任意字符 、\1代表匹配第一个括号、+代表与第一个括号匹配的字符可以有多个,例如AAAA,没有+的话只能匹配AA
(.)\\1(.)\\2 => (.)代表任意字符 、\1代表匹配第一个括号、\2代表匹配第二个括号
注意:类似于\d是数字,但是字符串中\是转义字符,所以表达\1或者\2要写作\\1和\\2,数字表示匹配第几个括号
//叠词 快快乐乐,高高兴兴
String regex = "(.)\\1(.)\\2";
System.out.println("快快乐乐".matches(regex));//true
System.out.println("快乐乐乐".matches(regex));//false
System.out.println("高高兴兴".matches(regex));//true
System.out.println("死啦死啦".matches(regex));//false
//叠词 死啦死啦,高兴高兴
String regex2 = "(..)\\1";
System.out.println("死啦死啦".matches(regex2));//true
System.out.println("高兴高兴".matches(regex2));//true
System.out.println("快快乐乐".matches(regex2));//false
String regex = "(.)(.)\\2\\1";
System.out.println("死啦啦死".matches(regex));//true
Java源码实现:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int line = scanner.nextInt();
scanner.nextLine();
for (int i = 0; i < line; i++) {
System.out.println(scanner.nextLine().replaceAll("(.)\\1+","$1$1").replaceAll("(.)\\1(.)\\2","$1$1$2"));
}
}
}
10.【字节跳动】万万没想到之抓捕孔连顺
我叫王大锤,是一名特工。我刚刚接到任务:在字节跳动大街进行埋伏,抓捕恐怖分子孔连顺。和我一起行动的还有另外两名特工,我提议
1>我们在字节跳动大街的N个建筑中选定3个埋伏地点。
2>为了相互照应,我们决定相距最远的两名特工间的距离不超过D。
我特喵是个天才! 经过精密的计算,我们从X种可行的埋伏方案中选择了一种。这个方案万无一失,颤抖吧,孔连顺!
……
万万没想到,计划还是失败了,孔连顺化妆成小龙女,混在cosplay的队伍中逃出了字节跳动大街。只怪他的伪装太成功了,就是杨过本人来了也发现不了的!
请听题:给定N(可选作为埋伏点的建筑物数)、D(相距最远的两名特工间的距离的最大值)以及可选建筑的坐标,计算在这次行动中,大锤的小队有多少种埋伏选择。
注意:
1>两个特工不能埋伏在同一地点
2.>三个特工是等价的:即同样的位置组合(A, B, C) 只算一种埋伏方法,不能因“特工之间互换位置”而重复使用
输入描述:
第一行包含空格分隔的两个数字 N和D(1 ≤ N ≤ 1000000; 1 ≤ D ≤ 1000000)
第二行包含N个建筑物的的位置,每个位置用一个整数(取值区间为[0, 1000000])表示,从小到大排列(将字节跳动大街看做一条数轴)
输出描述:
一个数字,表示不同埋伏方案的数量。结果可能溢出,请对 99997867 取模
输入例子1:
4 3
1 2 3 4
输出例子1:
4
例子说明1:
可选方案 (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)
解题思路:
从题目要求来看,其实就是从N个节点中选取三个,两两之间的差值不大于D
Java源码实现:
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt(); // 建筑物个数
int D = scanner.nextInt(); // 两人间最大的距离
int[] builds = new int[N];
for (int i = 0; i < N; i++) {
builds[i] = scanner.nextInt();
}
getAllWay(builds,D);
}
private static void getAllWay (int[] builds,int D) {
int mod = 99997867;
int count = 0;
for (int i = 0; i < builds.length - 2; i++) {
for (int j = i + 1; j < builds.length - 1;j++) {
if (builds[j] - builds[i] > D) {
break;
}
for (int k = j + 1; k < builds.length;k++) {
if (builds[k] - builds[j] > D) {
break;
}
count++;
System.out.println("当前方案" + builds[i] + "," + builds[j] + "," +
builds[k]);
}
}
}
System.out.println("共有" + (int) (count % mod) + "种方案");
}
}
11.【字节跳动】雀魂启动
小包最近迷上了一款叫做雀魂的麻将游戏,但是这个游戏规则太复杂,小包玩了几个月了还是输多赢少。
于是生气的小包根据游戏简化了一下规则发明了一种新的麻将,只留下一种花色,并且去除了一些特殊和牌方式(例如七对子等),具体的规则如下:
- 总共有36张牌,每张牌是1~9。每个数字4张牌。
- 你手里有其中的14张牌,如果这14张牌满足如下条件,即算作和牌
- 14张牌中有2张相同数字的牌,称为雀头。
- 除去上述2张牌,剩下12张牌可以组成4个顺子或刻子。顺子的意思是递增的连续3个数字牌(例如234,567等),刻子的意思是相同数字的3个数字牌(例如111,777)
例如:
1 1 1 2 2 2 6 6 6 7 7 7 9 9 可以组成1,2,6,7的4个刻子和9的雀头,可以和牌
1 1 1 1 2 2 3 3 5 6 7 7 8 9 用1做雀头,组123,123,567,789的四个顺子,可以和牌
1 1 1 2 2 2 3 3 3 5 6 7 7 9 无论用1 2 3 7哪个做雀头,都无法组成和牌的条件。
现在,小包从36张牌中抽取了13张牌,他想知道在剩下的23张牌中,再取一张牌,取到哪几种数字牌可以和牌。
输入描述:
输入只有一行,包含13个数字,用空格分隔,每个数字在1~9之间,数据保证同种数字最多出现4次。
输出描述:
输出同样是一行,包含1个或以上的数字。代表他再取到哪些牌可以和牌。若满足条件的有多种牌,请按从小到大的顺序输出。若没有满足条件的牌,请输出一个数字0
输入例子1:
1 1 1 2 2 2 5 5 5 6 6 6 9
输出例子1:
9
例子说明1:
可以组成1,2,6,7的4个刻子和9的雀头
Java源码实现(转载):
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] cards = new int[13];
int[] state = new int[9]; // 牌的大小1-9,用于存储1-9的牌的个数
int[] stateArr = new int[9];
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < 13; i++) {
int num = scanner.nextInt();
cards[i] = num;
state[num - 1]++;
}
for (int i = 0; i < 9; i++) { // 判断再加入哪张牌就可以和牌了
if (state[i] < 4) {
System.arraycopy(state,0,stateArr,0,9);
stateArr[i]++;
if(checkCanHu(stateArr,14,false)) res.add(i+1);
}
}
if (res.isEmpty()) System.out.println(0);
else {
StringBuffer sbf = new StringBuffer();
sbf.append(res.get(0));
for (int i = 1; i < res.size(); i++) {
sbf.append(" ");
sbf.append(res.get(i));
}
System.out.println(sbf.toString());
}
}
private static boolean checkCanHu(int[] arr,int total,boolean hasHead){
if (total == 0) return true;
if (!hasHead) {
for (int i = 0; i < 9; i++) {
if (arr[i] >= 2) {
arr[i] -= 2;
if (checkCanHu(arr, total - 2, true)) return true;
arr[i] += 2;
}
}
return false;
} else {
for (int i = 0; i < 9; i++) {
if (arr[i] > 0) {
if (arr[i] >= 3) {
arr[i] -= 3;
if (checkCanHu(arr, total - 3, true)) return true;
arr[i] += 3;
}
if (i + 2 < 9 && arr[i + 1] > 0 && arr[i + 2] > 0) {
arr[i]--;
arr[i + 1]--;
arr[i + 2]--;
if (checkCanHu(arr, total - 3, true)) return true;
arr[i]++;
arr[i + 1]++;
arr[i + 2]++;
}
}
}
}
return false;
}
}
12.