#include "bits/stdc++.h"
using namespace std;
#define FOR(i,j,k) for(int (i)=(j);(i)<(int)(k);++(i))
#define rep(i,j) FOR(i,0,j)
#define each(x,y) for(auto &(x):(y))
#define mp make_pair
#define mt make_tuple
#define all(x) (x).begin(),(x).end()
#define debug(x) cout<<#x<<": "<<(x)<<endl
#define smax(x,y) (x)=max((x),(y))
#define smin(x,y) (x)=min((x),(y))
#define MEM(x,y) memset((x),(y),sizeof (x))
#define sz(x) (int)(x).size()
#define pb push_back
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<ll> vll;

/*
強連結成分分解
O(|V|+|E|)
*/
struct SCC{
    int V;
    vector<vector<int>> G, rG;
    vector<int> vs, cmp, used;

    SCC(int n)
        : V(n), G(n), rG(n), used(n), cmp(n){}

    void add_edge(int from, int to){
        G[from].push_back(to);
        rG[to].push_back(from);
    }

    void dfs(int v) {
        used[v] = 1;
        for (int i = 0; i < G[v].size(); ++i)
            if (!used[G[v][i]]) dfs(G[v][i]);
        vs.push_back(v);
    }

    void rdfs(int v, int k){
        used[v] = 1;
        cmp[v] = k;
        for (int i = 0; i < rG[v].size(); ++i)
            if (!used[rG[v][i]]) rdfs(rG[v][i], k);
    }

    int scc(){
        fill(used.begin(), used.end(), 0);
        vs.clear();
        for (int v = 0; v < V; ++v)
            if (!used[v]) dfs(v);
        fill(used.begin(), used.end(), 0);
        int k = 0;
        for (int i = (int)vs.size() - 1; i >= 0; --i)
            if (!used[vs[i]]) rdfs(vs[i], k++);
        return k;
    }
};

/*
2-SAT
2-satisfiability
n: 変数の数
clauses: 節(iかつj)
imps: 論理包含(i=>j)
節および論理包含においてiの否定はi+nで与えるものとする。
戻り値: 真偽の割り当て(1:true, 0:false)、ただし、充足不可能ならば空とする。
検証済み:
http://yukicoder.me/problems/no/470
No.470 Inverse S+T Problem - yukicoder
*/
vector<int> twoSAT(int n, vector<pii> clauses, vector<pii> imps=vector<pii>()) {
    SCC scc(n * 2);
    for(auto clause : clauses) {
        int a, b;
        tie(a, b) = clause;
        int na = (a + n) % (n<<1);
        int nb = (b + n) % (n<<1);
        scc.add_edge(na, b);
        scc.add_edge(nb, a);
    }
    for(auto imp : imps) {
        scc.add_edge(imp.first, imp.second);
    }
    scc.scc();
    for(int i = 0; i < n; ++i) {
        if(scc.cmp[i] == scc.cmp[i + n]) {
            return vector<int>();
        }
    }
    vector<int> res(n);
    for(int i = 0; i < n; ++i) {
        res[i] = scc.cmp[i] > scc.cmp[i + n];
    }
    return res;
}

int n, x[10000], y[10000], m = 1, M, z[20000];
// 節のうち共通のもの
vector<pii> C, c, I;

void query(int a, int b, int k, int l, int r, int p){
    if(r <= a || b <= l) return;
    if(a <= l&&r <= b) {
        // pを使うかつkを使う　はだめ
        // <=> pを使わないまたはkを使わない
        c.emplace_back(m + p + M, k + M);
    } else{
        query(a,b,k<<1,l,(l+r)>>1, p);
        query(a,b,(k<<1)|1,(l+r)>>1,r, p);
    }
}

// 距離はd以上
bool check(int d) {
    if(d == 0)return true;
    c = C;
    rep(i, 2 * n) {
        // 距離がd未満のうち左にあるもの
        int l = lower_bound(z, z + i, z[i] - d + 1) - z;
        if(l != i) query(l, i, 1, 0, m, i);
        int r = lower_bound(z + 1, z + 2 * n, z[i] + d) - z;
        if(r != i + 1 && i + 1 < 2 * n) query(i + 1, r, 1, 0, m, i);
    }

    auto tf = twoSAT(M, c, I);
    return sz(tf) != 0;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    rep(i, n)cin >> x[i] >> y[i];

    // 葉の数
    while(m < n * 2)m *= 2;
    // セグメントの数
    M = m * 2;

    vector<pii> zi;
    rep(i, n) {
        zi.emplace_back(x[i], i);
        zi.emplace_back(y[i], i);
    }
    sort(all(zi));
    vi id(n, -1);
    rep(i, 2 * n) {
        int k;
        tie(z[i], k) = zi[i];
        if(id[k] == -1) {
            id[k] = i;
        } else {
            int j = id[k];
            // xとyを両方使ってしまうのはだめ
            // <=> xを使わないまたはyを使わない
            C.emplace_back(i + m + M, j + m + M);
            // xとyの両方とも使わないのはだめ
            // <=> xかyのどちらかは使う
            C.emplace_back(i + m, j + m);
        }
    }

    for(int i = m - 1; i >= 1; --i) {
        int l = i * 2, r = i * 2 + 1;
        I.emplace_back(l, i);
        I.emplace_back(r, i);
    }

    int l = 0, r = 1000000000;
    while(r - l > 1) {
        int d = (l + r) >> 1;
        (check(d) ? l : r) = d;
    }
    cout << l << endl;
}


Measured memory_bytes: 44536