二维矩阵求极小值

问题描述

给定一个不包含重复元素的N行M列二维矩阵,求矩阵的极小值。极小值的定义如下:若一个值是极小值,四连通方向上的的不越界的邻居都比它大。

思路

二维比较难想,我们从一维说起。
对于一维数组来说,如何寻找极小值?
二分法,找到中间位置x,如果x-1处的元素比x+1处的元素小,那么0~x-1之间必然存在一个极小值,从而缩小了范围。

升到二维,这个问题等价于。在平原上,寻找一个坑。这其实非常简单,我们只需要任选一点,从这个点出发始终朝着低处走,一定能够找到极小值点。

升到二维,首先也要想到分治法,降低复杂度。
对于矩阵较长的那个轴,二分之,切一刀。在刀痕处寻找极小值,极小值所在的那一侧必然是包含极小值的。

总之,这个问题只有一个思路:目前发现的最小值所在的区域一定包含极小值。关键在于划分区域的时候要严格保证最小值不会流出区域。

代码

import java.util.Random;

class Main {
int[][] a;
Random r = new Random();

void generate() {
    int rows = r.nextInt(10) + 5;
    int cols = r.nextInt(10) + 5;
    a = new int[rows][cols];
    int b[] = new int[rows * cols];
    for (int i = 0; i < b.length; i++) b[i] = i;
    for (int i = 0; i < b.length; i++) {
        int next = r.nextInt(b.length - i) + i;
        int temp = b[i];
        b[i] = b[next];
        b[next] = temp;
    }
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            a[i][j] = b[i * cols + j];
        }
    }
}

class Pos {
    int x, y;
    int value;

    Pos(int x, int y, int value) {
        this.x = x;
        this.y = y;
        this.value = value;
    }
}

boolean legal(int x, int y) {
    return x >= 0 && y >= 0 && x < a.length && y < a[0].length;
}

int dir[][] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

boolean isMinimum(int i, int j) {
    for (int k = 0; k < dir.length; k++) {
        int x = i + dir[k][0];
        int y = j + dir[k][1];
        if (legal(x, y)) {
            if (a[x][y] < a[i][j]) {
                return false;
            }
        }
    }
    return true;
}

Pos good(int fx, int fy, int tx, int ty, Pos min) {
    if (fx + 1 == tx && fy + 1 == ty) return new Pos(fx, fy, a[fx][fy]);
    if (tx - fx < ty - fy) {//二分长轴
        int my = (ty + fy) >> 1;
        for (int i = fx; i < tx; i++) {
            if (a[i][my] < min.value) {
                min.x = i;
                min.y = my;
                min.value = a[i][my];
            }
        }
        int minx = min.x, miny = min.y;
        for (int i = 0; i < dir.length; i++) {
            int x = minx + dir[i][0], y = miny + dir[i][1];
            if (legal(x, y) && a[x][y] < min.value) {
                min.x = x;
                min.y = y;
                min.value = a[x][y];
            }
        }
        if (min.y >= my) {
            return good(fx, my, tx, ty, min);
        } else {
            return good(fx, fy, tx, my, min);
        }
    } else {
        int mx = (tx + fx) >> 1;
        for (int i = fy; i < ty; i++) {
            if (a[mx][i] < min.value) {
                min.x = mx;
                min.y = i;
                min.value = a[mx][i];
            }
        }
        int minx = min.x, miny = min.y;
        for (int i = 0; i < dir.length; i++) {
            int x = minx + dir[i][0];
            int y = miny + dir[i][1];
            if (legal(x, y) && a[x][y] < min.value) {
                min.x = x;
                min.y = y;
                min.value = a[x][y];
            }
        }
        if (min.x >= mx) {
            return good(mx, fy, tx, ty, min);
        } else {
            return good(fx, fy, mx, ty, min);
        }
    }
}


Main() {
    for (int t = 0; t < 100; t++) {
        generate();
        Pos p = good(0, 0, a.length, a[0].length, new Pos(-1, -1, Integer.MAX_VALUE));
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a[i].length; j++) {
                System.out.printf(String.format("%4d", a[i][j]));
            }
            System.out.println();
        }
        System.out.println(p.x + " " + p.y + " " + p.value);
        if (!isMinimum(p.x, p.y)) {
            throw new RuntimeException("error");
        }
    }
}

public static void main(String[] args) {
    new Main();
}
}
原文地址:https://www.cnblogs.com/weiyinfu/p/9574260.html