#include <bits/stdc++.h>
using namespace std;
inline void pisz(int n) { printf("%d\n", n); }
template <typename T, typename TT>
ostream& operator<<(ostream& s, pair<T, TT> t) {
  return s << "(" << t.first << "," << t.second << ")";
}
template <typename T>
ostream& operator<<(ostream& s, vector<T> t) {
  for (int(i) = 0; (i) < (((int)((t).size()))); ++(i)) s << t[i] << " ";
  return s;
}
int num[2048][2048];
bitset<1000> bs[1024];
int main() {
  int(n), (m);
  scanf("%d %d", &(n), &(m));
  for (int(i) = 0; (i) < (n); ++(i))
    for (int(j) = 0; (j) < (m); ++(j)) scanf("%d", &num[i][j]);
  vector<int> v;
  v.push_back(0);
  for (int(i) = 0; (i) < (n); ++(i))
    for (int(j) = 0; (j) < (m); ++(j)) v.push_back(num[i][j]);
  sort(v.begin(), v.end());
  v.erase(unique(v.begin(), v.end()), v.end());
  int from = 1, to = ((int)((v).size())) - 1, best = 0;
  while (from <= to) {
    const int k = (from + to) / 2, val = v[k];
    for (int(i) = 0; (i) < (n); ++(i))
      for (int(j) = 0; (j) < (m); ++(j)) bs[i].set(j, num[i][j] >= val);
    bool ok = 0;
    for (int(a) = (0); (a) <= (n - 2); ++a) {
      for (int(b) = (a + 1); (b) <= (n - 1); ++b) {
        if ((bs[a] & bs[b]).count() >= 2) {
          ok = 1;
          break;
        }
      }
      if (ok) break;
    }
    if (ok) {
      best = k;
      from = k + 1;
    } else {
      to = k - 1;
    }
  }
  pisz(v[best]);
}
