//#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;
}