【华为秋招机考三道编程题之一】华为校招留学生软件开发工程师-真题机考笔试/题目1最小矩阵宽度(Java & JS & Python & C)20240712

【华为秋招机考三道编程题之一】华为校招留学生软件开发工程师-真题机考笔试/题目1最小矩阵宽度(Java & JS & Python & C)20240712

题目描述

给定一个矩阵,包含 N * M 个整数,和一个包含 K 个整数的数组。

现在要求在这个矩阵中找一个宽度最小的子矩阵,要求子矩阵包含数组中所有的整数。

输入描述

第一行输入两个正整数 N,M,表示矩阵大小。

接下来 N 行 M 列表示矩阵内容。

下一行包含一个正整数 K。

下一行包含 K 个整数,表示所需包含的数组,K 个整数可能存在重复数字。

所有输入数据小于1000。

输出描述

输出包含一个整数,表示满足要求子矩阵的最小宽度,若找不到,输出-1。

用例

输入2 5 1 2 2 3 1 2 3 2 3 2 3 1 2 3
输出2
说明矩阵第0、3列包含了1,2,3,矩阵第3,4列包含了1,2,3

输入2 5 1 2 2 3 1 1 3 2 3 4 3 1 1 4
输出5
说明矩阵第1、2、3、4、5列包含了1、1、4

题目解析

华为在线题库_职豚​www.zhitunjiaoyu.com/qbank/qbank?id=135&title=%E5%8D%8E%E4%B8%BA%E8%BD%AF%E4%BB%B6%E6%9C%BA%E8%80%83&type=qbank

1.首先,我们需要将给定的矩阵转换为一个二维数组,以便后续操作。

2.然后,我们需要找到包含所需整数的子矩阵。为了实现这一点,我们可以使用滑动窗口的方法。我们从矩阵的第一列开始,逐步向右移动窗口,直到找到一个包含所有所需整数的子矩阵。在每次移动窗口时,我们需要检查当前窗口是否包含所有所需整数。如果包含,则更新最小宽度;如果不包含,则继续向右移动窗口。

3.最后,输出满足要求的子矩阵的最小宽度。如果没有找到满足要求的子矩阵,则输出-1。

JS算法源码

 const rl = require("readline").createInterface({ input: process.stdin });
const iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

(async function () {
  const [n, m] = (await readline()).split(" ").map(Number);
  const matrix = [];
  for (let i = 0; i < n; i++) {
    matrix.push((await readline()).split(" ").map(Number));
  }
  const k = parseInt(await readline());
  const nums = (await readline()).split(" ").map(Number);
  const cnts = new Array(1000).fill(0);
  for (let num of nums) {
    cnts[num]++;
  }

  function getResult() {
    let total = k;
    let minLen = Infinity;
    let l = 0;
    let r = 0;

    while (r < m) {
      for (let i = 0; i < n; i++) {
        const num = matrix[i][r];
        if (cnts[num]-- > 0) {
          total--;
        }
      }

      while (total == 0) {
        minLen = Math.min(minLen, r - l + 1);
        for (let i = 0; i < n; i++) {
          const num = matrix[i][l];
          if (cnts[num]++ >= 0) {
            total++;
          }
        }
        l++;
      }
      r++;
    }

    return minLen === Infinity ? -1 : minLen;
  }

  console.log(getResult());
})();

Java算法源码

import java.util.Scanner;

public class Main {
  static int n;  
  static int m;  
  static int[][] matrix;  

  static int k;  
  static int[] cnts;  

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    n = sc.nextInt();
    m = sc.nextInt();

    matrix = new int[n][m];

    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        matrix[i][j] = sc.nextInt();
      }
    }

    k = sc.nextInt();

    cnts = new int[1000];
    for (int i = 0; i < k; i++) {
      int num = sc.nextInt();
      cnts[num]++;
    }

    System.out.println(getResult());
  }

  public static int getResult() {
      int total = k;

     int minLen = Integer.MAX_VALUE;

     int l = 0;
     int r = 0;

      while (r < m) {

        for (int i = 0; i < n; i++) {
         int num = matrix[i][r];
           if (cnts[num]-- > 0) {
          total--;
        }
      }

        while (total == 0) {
          minLen = Math.min(minLen, r - l + 1);

          for (int i = 0; i < n; i++) {
          
          int num = matrix[i][l];

            if (cnts[num]++ >= 0) {
            total++;
          }
        }

         l++;
      }
 
      r++;
    }

    if (minLen == Integer.MAX_VALUE) {
      return -1;
    } else {
      return minLen;
    }
  }
}

Python算法源码

import sys
from collections import Counter

def count_numbers(nums):
    return Counter(nums)

def get_result(matrix, k, nums):
    total = k
    min_len = sys.maxsize
    left = 0
    right = 0

    while right < len(matrix[0]):
        for row in matrix:
            num_right = row[right]
            if nums[num_right] > 0:
                total -= 1
                nums[num_right] -= 1

        while total == 0:
            min_len = min(min_len, right - left + 1)

            for row in matrix:
                num_left = row[left]
                if nums[num_left] >= 0:
                    total += 1
                    nums[num_left] += 1

            left += 1

        right += 1

    if min_len == sys.maxsize:
        return -1
    else:
        return min_len

n, m = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(n)]
k = int(input())
nums = list(map(int, input().split()))

counted_nums = count_numbers(nums)
result = get_result(matrix, k, counted_nums)
print(result)

C算法源码

#include <stdio.h>
#include <limits.h>
#include <math.h>

#define MAX_SIZE 1000

int n, m;
int matrix[MAX_SIZE][MAX_SIZE];

int k;
int cnts[MAX_SIZE] = {0};

int getResult() {
     int total = k;

    int minLen = INT_MAX;

     int l = 0;
    int r = 0;

     while (r < m) {
        for (int i = 0; i < n; i++) {
             int num = matrix[i][r];

                    if (cnts[num]-- > 0) {
                total--;
            }
        }

         while (total == 0) {
            minLen = (int) fmin(minLen, r - l + 1);

             for (int i = 0; i < n; i++) {
               
                int num = matrix[i][l];

             
                if (cnts[num]++ >= 0) {
                    total++;
                }
            }

             l++;
        }

        r++;
    }

    if (minLen == INT_MAX) {
        return -1;
    } else {
        return minLen;
    }
}

int main() {
    scanf("%d %d", &n, &m);

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }

    scanf("%d", &k);

    for (int i = 0; i < k; i++) {
        int num;
        scanf("%d", &num);
        cnts[num]++;
    }

    printf("%d\n", getResult());

    return 0;
}

解题思路如下:

  1. 输入处理
  • 首先,程序读取矩阵的行数n和列数m
  • 接着,程序会读取n行输入,每行包含m个数字,用以构造矩阵matrix
  • 然后,读取一个整数k,表示需要在子矩阵中找到的数字种类数。
  • 最后,读取一系列数字,这些数字是需要在子矩阵中查找的数字。

  1. 统计数字
  • 使用Counter函数统计输入数字nums中每个数字的出现次数,得到counted_nums

  1. 查找最小子矩阵
  • 初始化totalk,表示当前子矩阵中还需要找到的数字种类数量。
  • 初始化min_len为最大整数,用于记录找到的最小子矩阵的宽度。
  • 使用双指针技巧(滑动窗口),leftright分别指向子矩阵的左右边界。
  • 遍历矩阵的每一列(通过right指针),在每列中检查每一行的数字,并更新totalcounted_nums
  • total变为0时,表示当前子矩阵包含了所有需要找的数字种类,此时尝试收缩左边界(通过left指针),并更新min_len
  • 继续移动右边界,直到遍历完所有列。

  1. 输出结果
  • 如果min_len仍然是初始化的最大整数值,表示没有找到包含所有需要数字种类的子矩阵,返回-1。
  • 否则,返回min_len,即包含所有需要数字种类的最小子矩阵的宽度。

需要注意的是,这个算法假设输入的矩阵matrix的每一行都具有相同的长度,且nums中的数字都是矩阵中可能出现的数字。算法的核心是使用滑动窗口技巧,在列方向上移动左右边界,以找到包含所有需要数字种类的最小子矩阵。

另外,程序中有一个小错误需要指出:在get_result函数中,当移动左边界时,应该检查nums[num_left]是否大于0,而不是大于等于0,因为当nums[num_left]等于0时,表示该数字在当前子矩阵中的数量已经满足要求,不需要再增加。因此,应该将下面的代码:

python复制代码
if nums[num_left] >= 0:

修改为:

python复制代码
if nums[num_left] > 0:

这样修改后,程序将能更准确地找到包含所有需要数字种类的最小子矩阵。

不过,由于你的程序逻辑中,counted_nums存储的是nums中每个数字的出现次数,而nums数组本身并未在get_result函数中使用,所以上述错误在实际执行中可能并不会导致问题。但为了代码的准确性和可读性,建议进行相应的修改。

最后,你的程序是寻找一个子矩阵,该子矩阵在列方向上包含所有指定的数字至少一次,且子矩阵的列数最少。这是一个典型的滑动窗口问题,通过动态地调整子矩阵的左右边界来找到最优解。

作为互联网求职大人和大厂的专业老师,我有以下几点建议给准备参加校招的年轻人:

清晰定位自己的职业方向:在参加校招之前,首先要明确自己的兴趣和擅长的领域,以及未来希望从事的工作方向。这样,在校招过程中可以更有针对性地选择适合自己的岗位和公司。

充分准备简历和面试:简历是求职者的第一张名片,一定要认真制作,突出自己的优势和特点。同时,面试是求职过程中非常关键的一环,需要提前了解公司背景和岗位要求,做好充分的准备。

关注行业动态和技术趋势:互联网行业变化迅速,了解最新的行业动态和技术趋势对于求职者来说非常重要。这不仅可以帮助你更好地选择适合自己的岗位,还可以在面试中展示出你对行业的了解和热情。

积极参与实习和项目经验:在校期间,尽可能多地参与实习和项目经验,这不仅可以提升自己的实践能力,还能在校招时作为自己的亮点呈现。

注意网络素养和社交礼仪:在互联网行业,网络素养和社交礼仪尤为重要。在参加校招的过程中,无论是线上交流还是线下面试,都要注意自己的言行举止,给人留下良好的第一印象。

保持积极心态和耐心:校招过程可能会遇到各种挑战和困难,但要保持积极的心态和足够的耐心。相信自己的能力和潜力,坚持不懈地努力,最终一定会找到适合自己的工作机会。

提前了解公司文化和价值观:在参加校招之前,建议提前了解目标公司的文化和价值观,看看自己是否与之契合。这样,在面试过程中可以更加自信地表达自己对公司的认同和期望。

希望准备参加校招的年轻人们能够充分准备、积极面对挑战,找到自己满意的工作机会。加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值