华为非AI方向笔试真题 - 任意矩形图案解锁路径验证

任意矩形图案解锁路径验证

华为OD笔试真题 5月27号 非AI方向 100分题型

题目内容

给定一个 M×NM \times NM×N 的矩形网格(M×N≤100M \times N \le 100M×N≤100),每个格子按照行优先顺序(从左到右,从上到下)依次填充正整数,起始值为 111。例如对于 3×33 \times 33×3 的网格:格子 (0,0)=1(0,0) = 1(0,0)=1,格子 (0,1)=2(0,1) = 2(0,1)=2,格子 (0,2)=3(0,2) = 3(0,2)=3,格子 (1,0)=4(1,0) = 4(1,0)=4,依此类推。

现输入一个整数序列,需判断该序列是否能构成网格中的一条有效解锁路径,需满足以下条件:

  1. 输入的整数序列的任意两个相邻的数字,在对应的网格中需要相邻。 网格中任意一个格子,其相邻的格子包括其上、下、左、右、左上、右上、左下、右下共 888 个方向的格子(若存在)。

注:数字 222 的相邻格子有 111、333、444、555、666;

注:数字 555 的相邻格子有 111、222、333、444、666、777、888、999。

  1. 序列中任意两个相邻数字组成的路径不能重复。

这里的路径重复是指包括正向和反向的。

以该网格为例,假如序列中出现了路径 (2,5)(2,5)(2,5),后续不能再出现路径 (2,5)(2,5)(2,5) 和 (5,2)(5,2)(5,2) 了。

举例1 ::整数序列 {1,2,3,5,7,81,2,3,5,7,81,2,3,5,7,8} 满足解锁条件,因为格子 111 和格子 222,格子 222 和格子 333,格子 333 和格子 555,格子 555 和格子 777,格子 777 和格子 888 相邻。

举例2 :整数序列 {1,2,3,4,71,2,3,4,71,2,3,4,7} 不满足解锁条件,因为格子 333 和格子 444 不相邻(标记 111)

举例3 :整数序列 {1,2,5,8,5,61,2,5,8,5,61,2,5,8,5,6} 不满足解锁条件,因为格子 555 和格子 888 构成的边与格子 888 与格子 555 构成的边重复了(标记 111 和标记 222)

输入描述

  • 矩阵网格的行数 mmm(1≤m≤1001 \le m \le 1001≤m≤100)
  • 矩阵网格的列数 nnn(1≤n≤1001 \le n \le 1001≤n≤100)
  • 待解锁的序列个数 nnn(1≤n≤51 \le n \le 51≤n≤5)
  • 待解锁的序列 sequencesequencesequence(1≤sequence≤m×n1 \le \text{sequence} \le m \times n1≤sequence≤m×n,sequencesequencesequence size\[\]size\[\]size\[\] 大于 111)

输出描述

  • 输出所有可解锁的序列。
  • 多个可解锁的序列按照输入的序列顺序输出,每个序列占一行。
  • 如果一个序列都没有,返回 falsefalsefalse。

样例1

输入

复制代码
3
3
4
1,2,5,8,5,6
1,2,3,4,7
1,2,3,5,7,8
1,2,3,5,7,4

输出

复制代码
1,2,3,5,7,8
1,2,3,5,7,4

说明

有两个可解锁的序列,最终输出可解锁的序列。

1,2,3,5,7,81,2,3,5,7,81,2,3,5,7,8

1,2,3,5,7,41,2,3,5,7,41,2,3,5,7,4

样例2

输入

复制代码
3
3
3
1,2,5,8,5,6
1,2,3,4,7
1,2,3,5,7,8

输出

复制代码
1,2,3,5,7,8

说明

333 // 表示 333 行

333 // 表示 333 列

333 // 表示有 333 个待解锁的序列

整数序列 {1,2,5,8,5,61,2,5,8,5,61,2,5,8,5,6} 不满足解锁条件

整数序列 {1,2,3,4,71,2,3,4,71,2,3,4,7} 不满足解锁条件

整数序列 {1,2,3,5,7,8} 满足解锁条件,因为格子 111 和格子 222、格子 222 和格子 333、格子 333 和格子 555、格子 555 和格子 777、格子 777 和格子 888 均相邻。

因此,最终输出可解锁的序列 1,2,3,5,7,81,2,3,5,7,81,2,3,5,7,8

样例3

输入

复制代码
3
3
1
1,2,5,8,5,6
1,2,3,4,7

输出

复制代码
false

说明

整数序列 {1,2,5,8,5,61,2,5,8,5,61,2,5,8,5,6} 不满足解锁条件。

整数序列 {1,2,3,4,71,2,3,4,71,2,3,4,7} 不满足解锁条件,因为格子 333 和格子 444 不相邻。

由于这 222 个序列都不满足解锁条件,因此输出 falsefalsefalse。

样例4

输入

复制代码
3
3
2
1,2,5,8,5,6
1,2,3,5,7,8

输出

复制代码
1,2,3,5,7,8

说明

333 // 表示 333 行

333 // 表示 333 列

333 // 表示有 222 个序列待判断是否可解锁

1,2,5,8,5,61,2,5,8,5,61,2,5,8,5,6 // 表示待解锁的整数序列

1,2,3,5,7,81,2,3,5,7,81,2,3,5,7,8 // 表示待解锁的整数序列

整数序列 {1,2,5,8,5,61,2,5,8,5,61,2,5,8,5,6} 不满足解锁条件,因为格子 555 和格子 888 构成的边与格子 888 和格子 555 构成的边重复了。

整数序列 1,2,3,5,7,81,2,3,5,7,81,2,3,5,7,8 满足解锁条件。

故最终输出 1,2,3,5,7,81,2,3,5,7,81,2,3,5,7,8

题解和思路

思路

实现思路:模拟

  1. 输入的整数序列的任意两个相邻的数字,在对应的网格中需要相邻,检验这个规格,可以分别计算对应两个数字对应{ax,ay} 、{bx,by}横坐标和纵坐标。做如下检验:
    • 两点不属于同一位置
    • 坐标未超过网格取余
    • 对应横、纵坐标 差值绝对值都不大于1
  2. 不允许路径重复可以使用集合进行处理。
  3. 按照 1、 2对路径进项检验合法性,合法的路径保存在结果数组
  4. 结果数组为空输出false,否则按顺序换行输出每个路径。

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int m, n;


// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<int> split(const string& str, const string& delimiter) {
    vector<int> result;
    size_t start = 0;
    size_t end = str.find(delimiter);
    while (end != string::npos) {
        result.push_back(stoi(str.substr(start, end - start)));
        start = end + delimiter.length();
        end = str.find(delimiter, start);
    }
    // 添加最后一个部分
    result.push_back(stoi(str.substr(start)));
    return result;
}


bool judge(string& seqStr) {
    
    vector<int> seq = split(seqStr, ",");
    // 预防重复
    set<pair<int,int>> s;
  
    int l = seq.size();
    for (int i = 0; i < l - 1; i++) {
        // 统一转换为0-index
        int a = seq[i] - 1;
        int b = seq[i + 1] - 1;
        if (a == b) {
            return false;
        }
        
        // 分别计算对应横坐标、纵坐标
        int ax = a / n, ay = a % n;
        int bx = b / n, by = b % n;
        
        // 超过边界
        if (ax >= m || bx >= m) {
            return false;
        }

        // 横纵坐标绝对值
        if (abs(ax - bx) > 1 || abs(ay - by) > 1) {
            return false;
        }
        
        // 路径重复
        if (s.count({a, b}) || s.count({b, a})) {
            return false;
        }
        
        s.insert({a, b});
    }
    return true;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int count;
    cin >> m;
    cin >> n;
    cin >> count;
    cin.ignore();
    vector<string> ans;

    
    while (count--) {
        string seq;
        getline(cin, seq);
        if (judge(seq)) {
            ans.push_back(seq);
        }
    }
    
    if (ans.empty()) {
        cout << "false";
        return 0;
    }
    for (int i = 0; i < ans.size(); i++) {
        cout << ans[i] << endl;
    }
    
}

Java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {

    static int m, n;

    static boolean judge(String seqStr) {

        String[] arr = seqStr.split(",");

        int[] seq = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            seq[i] = Integer.parseInt(arr[i]);
        }

        // 预防重复
        Set<String> set = new HashSet<>();

        int len = seq.length;

        for (int i = 0; i < len - 1; i++) {

            // 统一转换为0-index
            int a = seq[i] - 1;
            int b = seq[i + 1] - 1;

            if (a == b) {
                return false;
            }

            // 分别计算对应横坐标、纵坐标
            int ax = a / n;
            int ay = a % n;

            int bx = b / n;
            int by = b % n;

            // 超过边界
            if (ax >= m || bx >= m) {
                return false;
            }

            // 横纵坐标绝对值
            if (Math.abs(ax - bx) > 1 || Math.abs(ay - by) > 1) {
                return false;
            }

            // 路径重复
            String key1 = a + "#" + b;
            String key2 = b + "#" + a;

            if (set.contains(key1) || set.contains(key2)) {
                return false;
            }

            set.add(key1);
        }

        return true;
    }

    public static void main(String[] args) throws Exception {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        m = Integer.parseInt(br.readLine());
        n = Integer.parseInt(br.readLine());
        int count = Integer.parseInt(br.readLine());

        List<String> ans = new ArrayList<>();

        while (count-- > 0) {
            String seq = br.readLine();

            if (judge(seq)) {
                ans.add(seq);
            }
        }

        if (ans.isEmpty()) {
            System.out.print("false");
            return;
        }

        for (String s : ans) {
            System.out.println(s);
        }
    }
}

python

python 复制代码
m = int(input())
n = int(input())
count = int(input())


def judge(seq_str):
    seq = list(map(int, seq_str.split(",")))

    # 预防重复
    s = set()

    length = len(seq)

    for i in range(length - 1):

        # 统一转换为0-index
        a = seq[i] - 1
        b = seq[i + 1] - 1

        if a == b:
            return False

        # 分别计算对应横坐标、纵坐标
        ax, ay = divmod(a, n)
        bx, by = divmod(b, n)

        # 超过边界
        if ax >= m or bx >= m:
            return False

        # 横纵坐标绝对值
        if abs(ax - bx) > 1 or abs(ay - by) > 1:
            return False

        # 路径重复
        if (a, b) in s or (b, a) in s:
            return False

        s.add((a, b))

    return True


ans = []

for _ in range(count):
    seq = input().strip()

    if judge(seq):
        ans.append(seq)

if not ans:
    print("false", end="")
else:
    print("\n".join(ans), end="")

Javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const lines = [];

rl.on("line", line => {
    lines.push(line.trim());
});

rl.on("close", () => {

    let idx = 0;

    const m = Number(lines[idx++]);
    const n = Number(lines[idx++]);
    const count = Number(lines[idx++]);

    function judge(seqStr) {

        const seq = seqStr.split(",").map(Number);

        // 预防重复
        const set = new Set();

        const len = seq.length;

        for (let i = 0; i < len - 1; i++) {

            // 统一转换为0-index
            const a = seq[i] - 1;
            const b = seq[i + 1] - 1;

            if (a === b) {
                return false;
            }

            // 分别计算对应横坐标、纵坐标
            const ax = Math.floor(a / n);
            const ay = a % n;

            const bx = Math.floor(b / n);
            const by = b % n;

            // 超过边界
            if (ax >= m || bx >= m) {
                return false;
            }

            // 横纵坐标绝对值
            if (Math.abs(ax - bx) > 1 || Math.abs(ay - by) > 1) {
                return false;
            }

            // 路径重复
            const key1 = `${a},${b}`;
            const key2 = `${b},${a}`;

            if (set.has(key1) || set.has(key2)) {
                return false;
            }

            set.add(key1);
        }

        return true;
    }

    const ans = [];

    for (let i = 0; i < count; i++) {
        const seq = lines[idx++];

        if (judge(seq)) {
            ans.push(seq);
        }
    }

    if (ans.length === 0) {
        process.stdout.write("false");
    } else {
        process.stdout.write(ans.join("\n"));
    }
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

var m, n int

func judge(seqStr string) bool {

	arr := strings.Split(seqStr, ",")

	seq := make([]int, len(arr))

	for i, s := range arr {
		seq[i], _ = strconv.Atoi(s)
	}

	// 预防重复
	visited := make(map[[2]int]bool)

	length := len(seq)

	for i := 0; i < length-1; i++ {

		// 统一转换为0-index
		a := seq[i] - 1
		b := seq[i+1] - 1

		if a == b {
			return false
		}

		// 分别计算对应横坐标、纵坐标
		ax, ay := a/n, a%n
		bx, by := b/n, b%n

		// 超过边界
		if ax >= m || bx >= m {
			return false
		}

		// 横纵坐标绝对值
		if abs(ax-bx) > 1 || abs(ay-by) > 1 {
			return false
		}

		// 路径重复
		if visited[[2]int{a, b}] || visited[[2]int{b, a}] {
			return false
		}

		visited[[2]int{a, b}] = true
	}

	return true
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func main() {

	reader := bufio.NewReader(os.Stdin)

	fmt.Fscan(reader, &m)
	fmt.Fscan(reader, &n)

	var count int
	fmt.Fscan(reader, &count)

	reader.ReadString('\n')

	var ans []string

	for i := 0; i < count; i++ {

		seq, _ := reader.ReadString('\n')
		seq = strings.TrimSpace(seq)

		if judge(seq) {
			ans = append(ans, seq)
		}
	}

	if len(ans) == 0 {
		fmt.Print("false")
		return
	}

	for _, s := range ans {
		fmt.Println(s)
	}
}
相关推荐
co_wait1 小时前
【华为】OSPF协议Stub和NSSA区域
华为
●VON2 小时前
鸿蒙Flutter实战:异步回调mounted检查安全实践
flutter·华为·harmonyos·鸿蒙
●VON2 小时前
鸿蒙Flutter实战:MethodChannel桥接获取OHOS文件目录
flutter·华为·harmonyos·鸿蒙
HwJack202 小时前
HarmonyOS APP开发中Native 层崩溃信号全集与生存指南
华为·harmonyos
搜移IT科技3 小时前
华为发布 “韬定律”,半导体换道超车引市场重估
华为
co_wait3 小时前
【华为】OSPF邻接关系和LSA
华为·智能路由器
李二。3 小时前
鸿蒙原生ArkTS-太空探索新闻AI
人工智能·华为·harmonyos
慧海灵舟3 小时前
鸿蒙南向开发教程 Day 7:互斥锁(Mutex)
华为·harmonyos
●VON3 小时前
鸿蒙Flutter实战:IndexedStack保持Tab页面状态
flutter·华为·harmonyos·鸿蒙