腾讯2018秋招笔试真题
3、画家小Q
【题目描述】画家小 Q 又开始他的艺术创作。小 Q 拿出了一块有 NxM 像素格的画板, 画板初始状态是空白
的,用’X’表示。
小 Q 有他独特的绘画技巧,每次小 Q 会选择一条斜线, 如果斜线的方向形如’/’,即斜率为 1,小 Q 会选择这
条斜线中的一段格子,都涂画为蓝色,用’B’表示;如果对角线的方向形如’\’,即斜率为-1,小 Q 会选择这条
斜线中的一段格子,都涂画为黄色,用’Y’表示。
如果一个格子既被蓝色涂画过又被黄色涂画过,那么这个格子就会变成绿色,用’G’表示。
小 Q 已经有想画出的作品的样子, 请你帮他计算一下他最少需要多少次操作完成这幅画。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数 N 和 M(1 <= N, M <= 50), 表示画板的长宽。
接下来的 N 行包含 N 个长度为 M 的字符串, 其中包含字符’B’,’Y’,’G’,’X’,分别表示蓝色,黄色,绿色,空
白。整个表示小 Q 要完成的作品。
输出描述:
输出一个正整数, 表示小 Q 最少需要多少次操作完成绘画。
输入示例:
4 4
YXXB
XYGX
XBYY
BXXY
输出示例:
3
说明:
XXXX
XXXX
XXXX
XXXX
->
YXXX
XYXX
XXYX
XXXY
->
YXXB
XYBX
XBYX
BXXY
->
YXXB
XYGX
XBYY
BXXY
解题思路:
从(0,0)位置开始遍历
- 如果遍历到(i,j)位置为B——>则继续向左下方(i+1,j-1)和右上方(i-1,j+1)
遍历时,遇到将B置为X,遇到G置为(消除B)置为Y
count++; - 如果遍历到(i,j)位置为Y——>则继续向左上方(i-1,j-1)和右下方(i+1,j+1)
遍历时,遇到将Y置为X,遇到G置为(消除Y)置为B
count++; - 如果遍历到(i,j)位置为G——>则分别执行1,2
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
public class Main03 {
static char[][] chs = new char[50][50];
static int n;
static int m;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
for(int i = 0; i < n; i++) {
String str = in.next();
for(int j = 0; j < m; j++) {
chs[i][j] = str.charAt(j);
}
}
int count = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(chs[i][j] == 'B') {
dfs_B(i, j);
count++;
} else if(chs[i][j] == 'Y') {
dfs_Y(i, j);
count++;
} else if(chs[i][j] == 'G') {
dfs_B(i, j);
count++;
dfs_Y(i, j);
count++;
}
}
}
System.out.println(count);
}
private static void dfs_B(int i, int j) {
if(i >= 0 && i < n && j >= 0 && j < m && (chs[i][j] == 'B' || chs[i][j] == 'G')) {
if(chs[i][j] == 'B') {
chs[i][j] = 'X';
} else if(chs[i][j] == 'G'){
chs[i][j] = 'Y';
}
dfs_B(i + 1, j - 1);
dfs_B(i - 1, j + 1);
}
return ;
}
private static void dfs_Y(int i, int j) {
if(i >= 0 && i < n && j >= 0 && j < m && (chs[i][j] == 'Y' || chs[i][j] == 'G')) {
if(chs[i][j] == 'Y') {
chs[i][j] = 'X';
} else if(chs[i][j] == 'G'){
chs[i][j] = 'B';
}
dfs_Y(i - 1, j - 1);
dfs_Y(i + 1, j + 1);
}
return ;
}
}
4、贪吃的小Q
【题目描述】小 Q 的父母要出差 N 天,走之前给小 Q 留下了 M 块巧克力。小 Q 决定每天吃的巧克力数量不
少于前一天吃的一半,但是他又不想在父母回来之前的某一天没有巧克力吃,请问他第一天最多能吃多少
块巧克力
输入描述:
每个输入包含一个测试用例。
每 个 测 试 用 例 的 第 一 行 包 含 两 个 正 整 数 , 表 示 父 母 出 差 的 天 数 N(N<=50000) 和 巧 克 力 的 数 量
M(N<=M<=100000)。
输出描述:
输出一个数表示小 Q 第一天最多能吃多少块巧克力。
输入示例:
3 7
输出示例:
4
解题思路:
首先想到的是等比求和
首相为x是需要求的值,公比是1/2,一共有N项,满足下列方程
x + 1/2*x + …… + (1/2)^(N-1)*x = M
(等比数列求和公式)变形为——>
x*(1-(1/2)^N) / (1-1/2) = M
x = M / (2 * (1-(1/2)^N))
x求的的值即为最大值
如果x不为整数需向下取整
public class Main04 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int x = (int) Math.ceil((m / (2 * (1 - Math.pow(0.5, n)))));
System.out.println(x);
}
}
然后只过了20%,:joy:
估计是浮点数的表示范围有限,在计算时数据有丢失
换策略
用二分查找
1 <= x <= M
x每次取中间值,求出第一天吃的巧克力为当前值是需要的总共巧克力与M比较
import java.util.Scanner;
public class Main04_2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int low = 1;
int high = m;
while(low < high) {
int mid = (low + high + 1) >> 1;// /2
int need = sum(n, mid);
if(need > m) {
high = mid - 1;
} else if(need == m) {
high = mid;
break;
} else {
low = mid;
}
}
System.out.println(high);
}
private static int sum(int n, int mid) {
int need = 0;
for(int i = 0; i < n; i++) {
need += mid;
mid = (mid + 1) >> 1; //不小于前一天的一半,向上取整
}
return need;
}
}