一、
给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大,要求时间复杂度:O(n),空间复杂度:O(1)
输入描述:
无序整数数组A[n]
输出描述:
满足条件的最大乘积
示例1
输入
3 4 1 2
输出
24
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n = sc.nextInt();
/* 两种情况:1、三个数都是正数,取三个最大整数
* 2、两个最小负数和一个最大正数
*/
int max[] = new int[3];
int min[] = new int[2];
Arrays.fill(max, Integer.MIN_VALUE);
Arrays.fill(min, Integer.MAX_VALUE);
for (int i = 0; i < n; i++) {
int cur = sc.nextInt();
if(cur > max[0]) {
max[2] = max[1];
max[1] = max[0];
max[0] = cur;
} else if(cur > max[1]) {
max[2] = max[1];
max[1] = cur;
} else if(cur > max[2]) {
max[2] = cur;
}
if(cur < min[0]) {
min[1] = min[0];
min[0] = cur;
} else if(cur < min[1]) {
min[1] = cur;
}
}
System.out.println(Math.max((long)min[0]*min[1]*max[0], (long)max[0]*max[1]*max[2]));
sc.close();
}
}
二、
有两个用字符串表示的非常大的大整数,算出他们的乘积,也是用字符串表示。不能用系统自带的大整数类型。
输入描述:
空格分隔的两个字符串,代表输入的两个大整数
输出描述:
输入的乘积,用字符串表示
示例1
输入
72106547548473106236 982161082972751393
输出
70820244829634538040848656466105986748
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String a = sc.next();
String b = sc.next();
sc.close();
int result[] = new int[a.length() + b.length()];//两个数相乘,结果的位数必小于两个数位数之和
int n = a.length();
int m = b.length();
a = new StringBuilder(a).reverse().toString();
b = new StringBuilder(b).reverse().toString();
for(int i = 0; i < n; i++) {//先算没有进位的两个数相乘
for(int j = 0; j < m; j++) {
result[i + j] += (a.charAt(i) - '0') * (b.charAt(j) - '0');
}
}
StringBuffer sb = new StringBuffer();
for(int i = 0; i < result.length; i++) {//处理进位问题
int remain = result[i] % 10;
int carry = result[i] / 10;
sb.append(remain);
if(i < result.length - 1) {//防止数组越界
result[i + 1] += carry;
}
}
sb.reverse();//处理顺序是尾部在头,所以应该反转
while(sb.length() > 0 && sb.charAt(0) == '0') {//result数组长度可能稍大,最后几个数为0
sb.deleteCharAt(0);
}
System.out.println(sb.toString());
}
}
三、
六一儿童节,老师带了很多好吃的巧克力到幼儿园。
每块巧克力j的重量为w[j],对于每个小朋友i,当他分到的巧克力大小达到h[i] (即w[j]>=h[i]),他才会上去表演节目。
老师的目标是将巧克力分发给孩子们,使得最多的小孩上台表演。可以保证每个w[i]> 0且不能将多块巧克力分给一个孩子或将一块分给多个孩子。
输入描述:
第一行:n,表示h数组元素个数
第二行:n个h数组元素
第三行:m,表示w数组元素个数
第四行:m个w数组元素
输出描述:
上台表演学生人数
示例1
输入
3
2 2 3
2
3 1
输出
1
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n = sc.nextInt();
int h[] = new int[n];
for(int i = 0; i < n; i++) {
h[i] = sc.nextInt();
}
int m = sc.nextInt();
int w[] = new int[m];
for(int i = 0; i < m;i++) {
w[i] = sc.nextInt();
}
sc.close();
//给需求最少的人最小的巧克力
Arrays.sort(h);
Arrays.sort(w);
int res = 0;
for(int i = m - 1, j = n - 1; i >= 0 && j >= 0; j--) {
if(w[i] >= h[j]) {
res++;
i--;
}
}System.out.println(res);
}
}
四、
假设一个探险家被困在了地底的迷宫之中,要从当前位置开始找到一条通往迷宫出口的路径。
迷宫可以用一个二维矩阵组成,有的部分是墙,有的部分是路。
迷宫之中有的路上还有门,每扇门都在迷宫的某个地方有与之匹配的钥匙,只有先拿到钥匙才能打开门。
请设计一个算法,帮助探险家找到脱困的最短路径。
如前所述,迷宫是通过一个二维矩阵表示的,每个元素的值的含义如下
0-墙,1-路,2-探险家的起始位置,3-迷宫的出口,大写字母-门,小写字母-对应大写字母所代表的门的钥匙
输入描述:
迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇。
输出描述:
路径的长度,是一个整数
输入
5 5
02111
01a0A
01003
01001
01111
输出
7
class Point {
int x;
int y;
int key;
public Point(int x, int y, int key) {
this.x = x;
this.y = y;
this.key = key;
}
}
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
char map[][] = new char[m][n];
sc.nextLine();
for (int i = 0;i<m;i++){
map[i] = sc.nextLine().toCharArray();
}
sc.close();
//迷宫问题一般都是用dfs。本题和一般的迷宫问题差别在找钥匙
int startx = 0, starty = 0, endx = 0, endy = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(map[i][j] == '2') {//找起点
startx = i;
starty = j;
}
if(map[i][j] == '3') {//找终点
endx = i;
endy = j;
}
}
}
System.out.println(bfs(map, m, n, startx, starty, endx, endy));
}
private static int bfs(char[][] map, int m, int n, int startx, int starty, int endx, int endy) {
Queue<Point> q = new LinkedList<>();
int dir[][] = {{0,1}, {0,-1}, {1,0}, {-1,0}};//每行一个方向
int[][][] keys = new int[m][n][1024];//keys存路径长度。最多10把钥匙,用十个01串存获取钥匙情况
for (int i = 0;i < m; i++){
for (int j = 0;j < n; j++){
for (int s = 0;s < 1024; s++){
keys[i][j][s] = -1;//初始化为-1表示未走过
}
}
}
q.add(new Point(startx, starty, 0));
keys[startx][starty][0] = 0;
while (!q.isEmpty()){
Point next = q.poll();
int x = next.x;
int y = next.y;
int key = next.key;
if (x == endx && y == endy) {//走到终点
//每遍历一层路径都加1,所以最先到达终点的可认为路径最短
return keys[x][y][key];
}
for (int i = 0; i < 4; i++){
x = next.x + dir[i][0];
y = next.y + dir[i][1];
key = next.key;
if(x < 0 || x >= m || y < 0 || y >= n || map[x][y] == '0') {//走出界或走到墙
continue;
}
if(keys[x][y][key] != -1) {//当前路径走过
continue;
}
if(map[x][y] >= 'a' && map[x][y] <= 'z'){//走到钥匙
key = key | (0x1 << (map[x][y] - 'a'));
}
if (map[x][y] >= 'A' && map[x][y] <= 'Z'){//走到门
if((key & (0x1 << (map[x][y] - 'A'))) <= 0){//没有钥匙
continue;
}
}
keys[x][y][key] = keys[next.x][next.y][next.key]+1;//标记是否走过,MAX表示未走过
q.add(new Point(x,y,key));
}
}
return -1;
}
}