//#pragma GCC optimize("Ofast,unroll-loops")
//#pragma GCC target("avx2,tune=native")
#include <bits/stdc++.h>
using namespace std;
#define file "o"
#define ff(i, a, b) for(auto i=(a); i<=(b); ++i)
#define ffr(i, b, a) for(auto i=(b); i>=(a); --i)
#define nl "\n"
#define ss " "
//#define pb push_back
#define pb emplace_back
#define fi first
#define se second
#define sz(s) (int)s.size()
#define all(s) (s).begin(), (s).end()
#define ms(a,x) memset(a, x, sizeof (a))
#define cn continue
#define re exit(0)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll ran(ll l, ll r)
{
return uniform_int_distribution<ll> (l, r)(rng);
}
inline void rf()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
if(fopen(file".inp","r"))
{
freopen(file".inp","r",stdin);
freopen(file".out","w",stdout);
}
}
const int mod=1e9+7;
const int maxn=3e5+15;
const ll inf=2e18;
template<typename T> inline void add(T &x, const T &y)
{
x+=y;
if(x>=mod) x-=mod;
if(x<0) x+=mod;
}
template<typename T> inline bool maxi(T &a, T b)
{
if(a>=b) return 0;
a=b; return 1;
}
template<typename T> inline bool mini(T &a, T b)
{
if(a<=b) return 0;
a=b; return 1;
}
static inline bool has2(const vector<uint64_t>& A, const vector<uint64_t>& B){
bool one = false;
for(size_t k = 0; k < A.size(); ++k){
uint64_t x = A[k] & B[k];
if(!x) continue;
if (x & (x - 1)) return true;
if (one) return true;
one = true;
}
return false;
}
int main(){
rf();
int m, n;
if(!(cin >> m >> n)) return 0;
vector<vector<long long>> a(m, vector<long long>(n));
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j)
cin >> a[i][j];
if(m > n){
vector<vector<long long>> t(n, vector<long long>(m));
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j)
t[j][i] = a[i][j];
a.swap(t);
swap(m, n);
}
vector<long long> vals;
vals.reserve((size_t)m * n);
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j)
vals.push_back(a[i][j]);
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
auto ok = [&](long long T)->bool{
int chunks = (n + 63) >> 6;
vector<vector<uint64_t>> row(m, vector<uint64_t>(chunks));
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(a[i][j] >= T){
int idx = j >> 6, off = j & 63;
row[i][idx] |= (uint64_t(1) << off);
}
}
}
for(int i = 0; i < m; ++i)
for(int j = i + 1; j < m; ++j)
if(has2(row[i], row[j])) return true;
return false;
};
int lo = 0, hi = (int)vals.size() - 1;
while(lo < hi){
int mid = (lo + hi + 1) >> 1;
if(ok(vals[mid])) lo = mid; else hi = mid - 1;
}
cout << vals[lo] << '\n';
return 0;
}