腾讯2018秋招笔试真题(2)

腾讯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;
    }
}

你可能感兴趣的:(算法)