// 2sat.cpp
#include <vector>
#include <iostream>

#define rep(i,n) for(int i=0; i<(n); i++)
#define rrep(i,n) for(int i=(n)-1; i>=0; i--)

using namespace std;

typedef vector<int> vi;

// scc.cppのコピー
// 強連結成分分解 (Strongly Connected Component)
struct SCCGraph: public vector<vi> {

	vector<int> order;    // 属する強連結成分の番号(トポロジカル順序になっている) まだ調べてない頂点は-1
	vector<int> vs;       // 帰りがけ順

	using vector::vector;	// 継承コンストラクタ
	SCCGraph(const vector<vi> &v): vector::vector(v) {}	// コピーコンストラクタを使用可能にする

	// a -> b の辺を追加する。push_back()でも同じ
	void add_edge(int a, int b){
		(*this)[a].push_back(b);
	}

	// scc()で使う
	void dfs(int n, int k, vector<vi> &v, vector<vi> &rv){
		order[n] = k;
		for(auto t: v[n]){
			rv[t].push_back(n);	// 逆辺のグラフを作成
			if( order[t] < 0 ) dfs(t, k, v, rv);
		}
		vs.push_back(n);
	}

	// 強連結成分分解を行う return:強連結成分の数
	int scc(){
		int N = size(), k = 0;
		vector<vi> rG(N), tmp(N);   // 辺を逆にしたグラフ用
		vs.clear();
		vs.reserve(2*N);
		order.assign(N, -1);
		rep(n,N) if( order[n] < 0 ) dfs(n, n, (*this), rG);
		order.assign(N, -1);
		rrep(i,vs.size()) if( order[ vs[i] ] < 0 ) dfs(vs[i], k++, rG, tmp);
		return k;
	}

	// 属する強連結成分が同じかどうか判定
	bool find(int x, int y){
		return order[x] == order[y];
	}

};
// 関数としてsccを使う。戻り値は、各ノードが所属する強連結成分の番号
vector<int> scc(const vector<vi> &v){
	SCCGraph g(v);
	g.scc();
	return g.order;
}


// 2-SAT
struct TwoSAT {
	SCCGraph graph;
	int N;
	vector<bool> val;	// 結果

	TwoSAT(int n): graph( (n+1)*2 ), val(n+1) {
		N = n;
	}

	void clear(){
		for(auto &&t: graph) t.clear();
	}

	// 辺( a -> b )を追加する。負の値は論理変数の否定(~a)を表す。
	// また、a の否定として a+N も使える。
	// a(>0) に対して、-a: 否定, a+N: 否定, -(a+N): 対偶=a
	void add_edge(int a, int b){
		if( a < 0 ) a = (3*N - a - 1) % (2*N) + 1;
		if( b < 0 ) b = (3*N - b - 1) % (2*N) + 1;
		graph.add_edge(a, b);
	}

	// 論理式( a V b ) を追加する。a,bは、論理変数の番号(0以外の整数)。否定は負の値で表す。
	void add_or(int a, int b){
		add_edge(-a, b);
		add_edge(-b, a);
	}

	// 判定を行う
	bool solve(){
		graph.scc();
		bool ret = true;
		for(int i=1; i <= N; i++){
			if( graph.order[i] == graph.order[N+i] ) ret = false;
			val[i] = (graph.order[i] > graph.order[N+i]);
		}
		return ret;
	}

	// 変数の値を取得する。
	bool value(int a){
		if( a < 0 ) return !val[-a];
		return val[a];
	}
};


TwoSAT sat(90005);
const int SegOff = 20003;
void setRelation(int k, int v){
	k += SegOff;
	v += SegOff;
	//cout << "setRelation: " << k << " " << v << endl;
	sat.add_or( -k, -v );
}

const int INF = 1e9+7;

template <typename T>
class SegTree{
	// セグメントツリーをたどる
	void prop(int l, int r, T v, int a, int b, int k=1){
		if( l <= a && b <= r ){
			// 完全に範囲内の場合
			setRelation(k, N+v);
		}else if( l < b && a < r ){
			// 中途半端に含まれる場合
			int m = (a+b) / 2;
			prop(l,r,v, a, m, k*2);
			prop(l,r,v, m, b, k*2+1);
		}
	}

public:
	int N;
	SegTree(int _N){
		// _N <= (N = 2^k) を満たすNを見つける
		N = 1;
		while( N < _N ) N<<=1;
	}
	void pRelation(){
		// 子がTrueなら、親もTrue
		rep(i,N) if(i){
			//cout << "pRelation: " << (SegOff + i*2) << " " << (SegOff + i) << endl;
			sat.add_edge(SegOff + i*2,   SegOff + i);
			sat.add_edge(SegOff + i*2+1, SegOff + i);
		}
	}
	void cRelation(int i, int v){
		int p = SegOff + N+i;
		//cout << "cRelation: " << p << " " << v << endl;
		sat.add_edge( p, v );
		sat.add_edge( v, p );
		sat.add_edge( -p, -v );
		sat.add_edge( -v, -p );
	}
	// セグメントツリーの更新(範囲に加算)
	void add(int l, int r, T v){
		//cout << "sg.add(): " << l << " " << r << " :" << v << endl;
		prop(l,r,v,0,N);
	}
};


// Atcoder ARC069 Flags (http://arc069.contest.atcoder.jp/tasks/arc069_d)
#include <map>
#include <algorithm>
typedef pair<int,int> pii;
int main(){
	int N;
	vector<pii> mp;
	SegTree<int> sg(20005);

	cin >> N;
	rep(i,N){
		int x, y;
		cin >> x >> y;
		mp.emplace_back( x, i+1 );
		mp.emplace_back( y, -(i+1) );
	}
	sort( mp.begin(), mp.end() );

	auto fn = [&](int m){
		//cout << "fn " << m << endl;
		sat.clear();
		sg.pRelation();
		rep(i, mp.size()) sg.cRelation(i, mp[i].second);
		// range relation
		rep(i, mp.size()){
			// down
			auto it = lower_bound(mp.begin(), mp.end(), pii(mp[i].first - m + 1, -INF));
			int pos = (it - mp.begin());
			sg.add( pos, i, i );
			// up
			it = lower_bound(mp.begin(), mp.end(),  pii(mp[i].first + m, -INF));
			pos = (it - mp.begin());
			sg.add( i+1, pos, i );
		}
		//cout << "setup finish" << endl;
		bool ret = sat.solve();
		//cout << "ret: " << ret << endl;
		return ret;
	};

	int l=0, r=1e9;
	while( r-l > 1 ){
		int m = (l+r) / 2;
		if( fn(m) ){
			l = m;
		}else{
			r = m;
		}
	}

	cout << l << endl;

	return 0;
}

Measured memory_bytes: 51732