source_code: import java.io.OutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Arrays;
  import java.io.IOException;
  import java.io.UncheckedIOException;
  import java.io.Closeable;
  import java.io.Writer;
  import java.io.OutputStreamWriter;
  import java.io.InputStream;
  
  /**
   * Built using CHelper plug-in
   * Actual solution is at the top
   */
  public class Main {
    public static void main(String[] args) throws Exception {
      Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 27);
      thread.start();
      thread.join();
    }
  
    static class TaskAdapter implements Runnable {
      @Override
        public void run() {
          InputStream inputStream = System.in;
          OutputStream outputStream = System.out;
          FastInput in = new FastInput(inputStream);
          FastOutput out = new FastOutput(outputStream);
          FElongatedMatrix solver = new FElongatedMatrix();
          solver.solve(1, in, out);
          out.close();
        }
    }
  
    static class FElongatedMatrix {
      public void solve(int testNumber, FastInput in, FastOutput out) {
        int n = in.readInt();
        int m = in.readInt();
        int[][] mat = new int[n][m];
        for (int i = 0; i < n; i++) {
          for (int j = 0; j < m; j++) {
            mat[i][j] = in.readInt();
          }
        }
  
        int[][] minDist = new int[n][n];
        SequenceUtils.deepFill(minDist, (int) 1e9);
        for (int i = 0; i < n; i++) {
          for (int j = 0; j < n; j++) {
            for (int k = 0; k < m; k++) {
              minDist[i][j] = Math.min(minDist[i][j], Math.abs(mat[i][k] - mat[j][k]));
            }
          }
        }
        int[][] minDistBetweenHeadAndTail = new int[n][n];
        SequenceUtils.deepFill(minDistBetweenHeadAndTail, (int) 1e9);
        for (int i = 0; i < n; i++) {
          for (int j = 0; j < n; j++) {
            for (int k = 1; k < m; k++) {
              minDistBetweenHeadAndTail[i][j] = Math.min(minDistBetweenHeadAndTail[i][j], Math.abs(mat[i][k] - mat[j][k - 1]));
            }
          }
        }
  
        Log2 log2 = new Log2();
        BitOperator bo = new BitOperator();
        int[][][] dp = new int[1 << n][n][n];
        for (int i = 1; i < (1 << n); i++) {
          if (i == Integer.lowestOneBit(i)) {
            dp[i][log2.floorLog(i)][log2.floorLog(i)] = (int) 1e9;
            continue;
          }
          for (int j = 0; j < n; j++) {
            for (int k = 0; k < n; k++) {
              if (bo.bitAt(i, j) == 0) {
                continue;
              }
              for (int t = 0; t < n; t++) {
                dp[i][j][k] = Math.max(dp[i][j][k],
                    Math.min(dp[bo.setBit(i, j, false)][t][k],
                      minDist[j][t]));
              }
            }
          }
        }
  
        int ans = 0;
        for (int i = 0; i < n; i++) {
          for (int j = 0; j < n; j++) {
            ans = Math.max(ans, Math.min(dp[(1 << n) - 1][i][j], minDistBetweenHeadAndTail[j][i]));
          }
        }
        out.println(ans);
      }
  
    }
  
    static class SequenceUtils {
      public static void deepFill(Object array, int val) {
        if (!array.getClass().isArray()) {
          throw new IllegalArgumentException();
        }
        if (array instanceof int[]) {
          int[] intArray = (int[]) array;
          Arrays.fill(intArray, val);
        } else {
          Object[] objArray = (Object[]) array;
          for (Object obj : objArray) {
            deepFill(obj, val);
          }
        }
      }
  
    }
  
    static class Log2 {
      public int floorLog(int x) {
        return 31 - Integer.numberOfLeadingZeros(x);
      }
  
    }
  
    static class FastInput {
      private final InputStream is;
      private byte[] buf = new byte[1 << 13];
      private int bufLen;
      private int bufOffset;
      private int next;
  
      public FastInput(InputStream is) {
        this.is = is;
      }
  
      private int read() {
        while (bufLen == bufOffset) {
          bufOffset = 0;
          try {
            bufLen = is.read(buf);
          } catch (IOException e) {
            bufLen = -1;
          }
          if (bufLen == -1) {
            return -1;
          }
        }
        return buf[bufOffset++];
      }
  
      public void skipBlank() {
        while (next >= 0 && next <= 32) {
          next = read();
        }
      }
  
      public int readInt() {
        int sign = 1;
  
        skipBlank();
        if (next == '+' || next == '-') {
          sign = next == '+' ? 1 : -1;
          next = read();
        }
  
        int val = 0;
        if (sign == 1) {
          while (next >= '0' && next <= '9') {
            val = val * 10 + next - '0';
            next = read();
          }
        } else {
          while (next >= '0' && next <= '9') {
            val = val * 10 - next + '0';
            next = read();
          }
        }
  
        return val;
      }
  
    }
  
    static class BitOperator {
      public int bitAt(int x, int i) {
        return (x >> i) & 1;
      }
  
      public int setBit(int x, int i, boolean v) {
        if (v) {
          x |= 1 << i;
        } else {
          x &= ~(1 << i);
        }
        return x;
      }
  
    }
  
    static class FastOutput implements AutoCloseable, Closeable {
      private StringBuilder cache = new StringBuilder(10 << 20);
      private final Writer os;
  
      public FastOutput(Writer os) {
        this.os = os;
      }
  
      public FastOutput(OutputStream os) {
        this(new OutputStreamWriter(os));
      }
  
      public FastOutput println(int c) {
        cache.append(c).append('\n');
        return this;
      }
  
      public FastOutput flush() {
        try {
          os.append(cache);
          os.flush();
          cache.setLength(0);
        } catch (IOException e) {
          throw new UncheckedIOException(e);
        }
        return this;
      }
  
      public void close() {
        flush();
        try {
          os.close();
        } catch (IOException e) {
          throw new UncheckedIOException(e);
        }
      }
  
      public String toString() {
        return cache.toString();
      }
  
    }
  }
  