小米笔试真题刷练(较难俩个)

1.

// 数独计数
// 小明最近热衷于数独游戏。在厌倦了传统数独后,他想到一个有趣的规则:有3x3的方格,
// 他要把1~9的这9个数字不重不漏地填入这9个方格,并且保证填入的每个数字周围没有临近数,
// 例如在中间位置填了数字4,那么数字3和5不能出现在数字4上下左右四个位置中任何一个。 
// 现在小明已经填上了几个数字,他想知道一共有多少种符合上述规则的填充方案,
// 当且仅当至少存在一个位置在这两种方案中填充的数字不同时,两种填充方案被认为是不同的。
// 对每组数据,有三行,每行三个整数。
// 这三行三列中的第i行第j列的数aij代表题面描述中的3x3方格对应位置的情况。
// 如果aij=0表示那个格子还未填充;如果是一个[1,9]范围内的整数表示小明已填好的数字。
// 保证至少有一个格子未填充,已填充的格子不会出现重复数字,但有可能不合法。
 

// 回溯法

// 检查当前位置是否可以放置数字num
// 功能:检查在网格的(row, col)位置放置数字num是否合法。
// 实现:
// 检查当前位置的上下左右四个方向(如果存在)是否已经有数字与num的绝对值之差为1。
// 如果有,则返回false,表示不能放置;否则返回true。
// 示例:
// 如果num = 4,且左边是3或5,则返回false。
bool isValid(const vector<vector<int>>& grid, int row, int col, int num) {
    // 检查上下左右四个方向
    if (row > 0 && abs(grid[row - 1][col] - num) == 1) return false;
    if (row < 2 && abs(grid[row + 1][col] - num) == 1) return false;
    if (col > 0 && abs(grid[row][col - 1] - num) == 1) return false;
    if (col < 2 && abs(grid[row][col + 1] - num) == 1) return false;
    return true;
}

// 回溯函数
// 功能:递归地尝试填充网格,并统计所有合法的填充方案数。
// 参数:
// grid:3x3的网格,表示当前填充状态。
// row和col:当前需要填充的位置。
// used:一个布尔数组,记录数字1到9是否已经被使用。
// 实现:
// 终止条件:
// 如果row == 3,表示所有行都已经填满,找到一个合法方案,返回1。
// 列越界处理:
// 如果col == 3,表示当前行已经填满,递归进入下一行的第0列。
// 跳过已填充的位置:
// 如果grid[row][col] != 0,表示当前位置已经有数字,直接跳到下一个位置。
// 尝试填充数字:
// 遍历数字1到9,尝试将未使用且合法的数字num放在(row, col)位置。
// 如果num可以放置,则标记为已使用,并递归填充下一个位置。
// 递归返回后,撤销当前选择(回溯),继续尝试其他数字。
// 返回结果:
// 返回当前分支的合法方案数。
int backtrack(vector<vector<int>>& grid, int row, int col, vector<bool>& used) {
    if (row == 3) {
        // 所有位置都填满了,找到一个合法方案
        return 1;
    }

    if (col == 3) {
        // 当前行填满了,转到下一行
        return backtrack(grid, row + 1, 0, used);
    }

    if (grid[row][col] != 0) {
        // 当前位置已经填了数字,直接跳到下一个位置
        return backtrack(grid, row, col + 1, used);
    }

    int count = 0;
    for (int num = 1; num <= 9; ++num) {
        if (!used[num] && isValid(grid, row, col, num)) {
            // 尝试放置数字num
            grid[row][col] = num;
            used[num] = true;
            count += backtrack(grid, row, col + 1, used);
            // 回溯
            grid[row][col] = 0;
            used[num] = false;
        }
    }
    return count;
}

2.// 小A爱魔法
// 小A一共会两种魔法,第一种魔法可以将纸上数字变为它的a倍,
// 比如在a=3时,他可以将666变成1998;
// 第二种魔法可以让纸上的数字循环右移一次,
// 比如12345在施加第二种魔法后会变成51234,119会变成911,
// 需要注意的是,小A无法对小于10或是以0为结尾的数施加第二种魔法。
// 纸上的数字初始是1,小A想将它变成自己的幸运数字b,那么请问小A至少需要施加几次魔法。
// 如果无论如何都无法将它变成b,请输出-1。

解题: bfs

int magic(int a, int b) {
    // bfs 查找
    queue<pair<int, int>> q; // 存储当前数字与步数
    
    q.push({ 1,0 });

    unordered_set<int> visited; // 记录已经访问过的数字
    visited.insert(1);
    while (!q.empty()) {
        auto current = q.front();
        q.pop();
        int num = current.first;
        int steps = current.second;

        if (num == b) {
            return steps; // 找到目标数字
        }

        // 尝试第一种魔法:乘以a
        int nextNum1 = magic_1(num, a);
        if (nextNum1 < 1e6 && visited.find(nextNum1) == visited.end()) {
            visited.insert(nextNum1);
            q.push({ nextNum1, steps + 1 });
        }

        // 尝试第二种魔法:循环右移
        int nextNum2 = magic_2(num);
        if (nextNum2 != -1 && visited.find(nextNum2) == visited.end()) {
            visited.insert(nextNum2);
            q.push({ nextNum2, steps + 1 });
        }
    }

    return -1; // 无法到达目标数字
}


int magic_1(int& num, int a) {
    return a * num;
}

int magic_2(int num) {
    if (num < 10 || num % 10 == 0) {
        return num;
    }
    int lastDigit = num % 10;
    int remaining = num / 10;
    int digits = 0;
    int temp = remaining;
    while (temp != 0) {
        temp /= 10;
        digits++;
    }
    int result = lastDigit;
    for (int i = 0; i < digits; ++i) {
        result *= 10;
    }
    result += remaining;
    return result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

01_

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值