Rust 练习册 98:探索矩阵中的鞍点

在数学和计算机科学中,矩阵是一个重要的数据结构,广泛应用于图形处理、机器学习、游戏开发等领域。今天我们来探讨一个有趣的矩阵问题——寻找鞍点(Saddle Points)。

什么是鞍点?

在数学上,鞍点是指在一个矩阵中,某个元素既是其所在行的最大值,又是其所在列的最小值。这个名字来源于它的形状类似马鞍——在某个方向上是最高点,而在另一个方向上是最低点。

举个例子,假设我们有一个矩阵:

[1 2 3]
[4 5 6]
[7 8 9]

在这个矩阵中,元素5既不是行最大值也不是列最小值,所以它不是鞍点。而如果我们将矩阵改为:

[1 2 3]
[4 1 6]
[7 8 9]

这时,元素1在其所在的行中是最小值,在其所在的列中是最大值,因此它是一个鞍点。

问题描述

在我们的练习中,需要实现这样一个函数:

pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    unimplemented!(
        "find the saddle points of the following matrix: {:?}",
        input
    )
}

这个函数接收一个二维矩阵作为参数,返回所有鞍点的位置坐标(行索引,列索引)组成的向量。

解决方案

要找到所有的鞍点,我们需要对矩阵中的每个元素进行检查:

  1. 对于每个元素,判断它是否是所在行的最大值
  2. 同时判断它是否是所在列的最小值
  3. 如果两个条件都满足,则该元素是一个鞍点

下面是完整的实现:

pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    // 处理空矩阵的情况
    if input.is_empty() || input[0].is_empty() {
        return vec![];
    }

    let rows = input.len();
    let cols = input[0].len();

    // 预计算每行的最大值和每列的最小值
    let mut row_max = vec![0; rows];
    let mut col_min = vec![u64::MAX; cols];

    for i in 0..rows {
        for j in 0..cols {
            row_max[i] = row_max[i].max(input[i][j]);
            col_min[j] = col_min[j].min(input[i][j]);
        }
    }

    // 查找鞍点
    let mut saddle_points = Vec::new();
    for i in 0..rows {
        for j in 0..cols {
            let value = input[i][j];
            // 检查是否同时满足行最大值和列最小值的条件
            if value == row_max[i] && value == col_min[j] {
                saddle_points.push((i, j));
            }
        }
    }

    saddle_points
}

测试案例详解

通过查看测试案例,我们可以更好地理解问题的各种边界情况:

#[test]
fn identify_single_saddle_point() {
    let input = vec![vec![9, 8, 7], vec![5, 3, 2], vec![6, 6, 7]];
    assert_eq!(vec![(1, 0)], find_saddle_points(&input));
}

在这个测试中,位置(1, 0)的元素5是第1行的最大值,同时也是第0列的最小值。

#[test]
fn identify_empty_matrix() {
    let input = vec![vec![], vec![], vec![]];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

空矩阵显然没有鞍点。

#[test]
fn multiple_saddle_points_in_col() {
    let input = vec![vec![4, 5, 4], vec![3, 5, 5], vec![1, 5, 4]];
    assert_eq!(
        vec![(0, 1), (1, 1), (2, 1)],
        find_sorted_saddle_points(&input)
    );
}

在这个例子中,第1列的所有元素都是5,且都是该列的最小值。同时它们也是各自行的最大值,因此这一列的所有元素都是鞍点。

#[test]
fn identify_all_saddle_points() {
    let input = vec![vec![5, 5, 5], vec![5, 5, 5], vec![5, 5, 5]];
    assert_eq!(
        vec![
            (0, 0),
            (0, 1),
            (0, 2),
            (1, 0),
            (1, 1),
            (1, 2),
            (2, 0),
            (2, 1),
            (2, 2)
        ],
        find_sorted_saddle_points(&input)
    );
}

当矩阵中所有元素都相等时,每个元素都是其所在行的最大值和所在列的最小值,因此所有位置都是鞍点。

算法优化

上述实现采用了预计算的方式,先计算出每行的最大值和每列的最小值,然后再查找符合条件的元素。这种方法的时间复杂度是O(rows × cols),比对每个元素单独计算其行和列的最值要高效得多。

实际应用

鞍点问题不仅仅是一个理论上的数学问题,它在实际中有很多应用:

  1. 博弈论:在零和游戏中,鞍点代表了最优策略
  2. 优化理论:在多变量函数中,鞍点是非局部极值的临界点
  3. 图像处理:用于特征检测和边缘识别
  4. 经济学:在供需模型中寻找平衡点

总结

通过这个练习,我们学会了:

  1. 如何处理二维矩阵数据
  2. 如何进行行列统计计算
  3. 如何优化算法避免重复计算
  4. 边界条件的处理

这些问题在实际编程中经常遇到,掌握这类问题的解决方法对我们提高编程能力很有帮助。Rust的安全性和性能优势使得它成为处理这类数值计算问题的理想选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

少湖说

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值