#include <bits/stdc++.h>
using namespace std;
const int NMAX = 16, MMAX = 10010;
const int INF = 0x7fffffff;
int n, m;
int ans;
int mval[NMAX][NMAX][2];
int matrix[NMAX][MMAX];
int f[NMAX][NMAX][1 << NMAX];
struct tup {
  int a, b, c;
};
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]);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      mval[i][j][0] = mval[i][j][1] = INF;
      for (int k = 0; k < m; k++) {
        mval[i][j][0] = min(mval[i][j][0], abs(matrix[i][k] - matrix[j][k]));
        if (k + 1 != m) {
          mval[i][j][1] =
              min(mval[i][j][1], abs(matrix[i][k] - matrix[j][k + 1]));
        }
      }
    }
  }
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
      for (int k = 0; k < (1 << n); k++) f[i][j][k] = -1;
  queue<tup> q;
  for (int i = 0; i < n; i++) {
    f[i][i][(1 << i)] = INF;
    q.push((tup){i, i, 1 << i});
  }
  while (!q.empty()) {
    int start = q.front().a;
    int last = q.front().b;
    int mask = q.front().c;
    q.pop();
    for (int i = 0; i < n; i++) {
      if (!(mask & (1 << i))) {
        int newmask = mask | (1 << i);
        if (f[start][i][newmask] == -1) q.push((tup){start, i, newmask});
        f[start][i][newmask] = max(f[start][i][newmask],
                                   min(f[start][last][mask], mval[last][i][0]));
      }
    }
  }
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      ans = max(ans, min(f[i][j][(1 << n) - 1], mval[j][i][1]));
    }
  }
  printf("%d\n", ans);
  return 0;
}
