#include <iostream>
#include <string>
#include <cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<iomanip>
#define _USE_MATH_DEFINES
#include <math.h>
#include <functional>
#include<complex>
using namespace std;

#define rep(i,x) for(ll i=0;i<x;i++)
#define repn(i,x) for(ll i=1;i<=x;i++)

typedef long long ll;
const ll INF = 1e17;
const ll MOD = 998244353;
const ll MAX = 4000001;
const long double eps = 1E-14;

ll max(ll a, ll b) {
	if (a > b) { return a; }
	return b;
}

ll min(ll a, ll b) {
	if (a > b) { return b; }
	return a;
}

ll gcd(ll a, ll b) {
	if (b == 0) { return a; }
	if (a < b) { return gcd(b, a); }
	return gcd(b, a % b);
}

ll lcm(ll a, ll b) {
	return a / gcd(a, b) * b;
}

struct edge {
	ll ind;
	ll fr;
	ll to;
	ll d;
};

class mint {
	long long x;
public:
	mint(long long x = 0) : x((x% MOD + MOD) % MOD) {}
	mint operator-() const {
		return mint(-x);
	}
	mint& operator+=(const mint& a) {
		if ((x += a.x) >= MOD) x -= MOD;
		return *this;
	}
	mint& operator-=(const mint& a) {
		if ((x += MOD - a.x) >= MOD) x -= MOD;
		return *this;
	}
	mint& operator*=(const  mint& a) {
		(x *= a.x) %= MOD;
		return *this;
	}
	mint operator+(const mint& a) const {
		mint res(*this);
		return res += a;
	}
	mint operator-(const mint& a) const {
		mint res(*this);
		return res -= a;
	}
	mint operator*(const mint& a) const {
		mint res(*this);
		return res *= a;
	}

	mint pow(ll t) const {
		if (!t) return 1;
		mint a = pow(t >> 1);
		a *= a;
		if (t & 1) a *= *this;
		return a;
	}

	// for prime MOD
	mint inv() const {
		return pow(MOD - 2);
	}
	mint& operator/=(const mint& a) {
		return (*this) *= a.inv();
	}
	mint operator/(const mint& a) const {
		mint res(*this);
		return res /= a;
	}

	friend ostream& operator<<(ostream& os, const mint& m) {
		os << m.x;
		return os;
	}
};

mint pw(mint a, ll b) {
	if (b == 0) { return 1; }
	mint ret = pw(a, b >> 1);
	ret *= ret;
	if (b & 1) { ret *= a; }
	return ret;
}

typedef vector<ll> vll;
typedef vector<vector<ll>> vvll;
typedef vector<vector<vector<ll>>> vvvll;

typedef vector<mint> vmint;
typedef vector<vector<mint>> vvmint;
typedef vector<vector<vector<mint>>> vvvmint;

/////////////////////////////////////
struct SCC {
	vector<vector<edge>> g;
	ll N;
	ll M;

	vector<vector<edge>> graph;//分解してできるグラフ
	vll ver;//元のグラフとの頂点の対応
	vll ed;//辺の対応(同じ成分に入る場合は、-頂点番号)

	vll kaeri;

	void dfs(ll v) {
		ver[v] = -1;
		for (edge e : g[v]) {
			ll w = e.to;
			if (ver[w] == -1) { continue; }
			dfs(w);
		}
		kaeri.push_back(v);
	}

	vector<vector<edge>> grev;
	void dfsrev(ll v, ll c) {
		ver[v] = c;
		for (edge e : grev[v]) {
			ll w = e.to;
			if (ver[w] != -1) { continue; }
			dfsrev(w, c);
		}
	}

	SCC(vector<vector<edge>> g0) {
		g = g0;
		N = g.size() - 1;
		M = 0;

		ver.assign(N + 1, 0);

		repn(v, N) {
			if (ver[v] == -1) { continue; }
			dfs(v);
		}

		grev.resize(N + 1);
		repn(v, N) {
			for (edge e : g[v]) {
				grev[e.to].push_back({ e.ind,e.to,e.fr,e.d });
				M++;
			}
		}

		reverse(kaeri.begin(), kaeri.end());

		ll c = 0;
		for (ll v : kaeri) {
			if (ver[v] != -1) { continue; }
			c++;
			dfsrev(v, c);
		}

		ed.assign(M + 1, 0);
		ll ind = 0;
		graph.resize(c + 1);
		repn(v, N) {
			for (edge e : g[v]) {
				ll X = ver[v];
				ll Y = ver[e.to];

				if (X == Y) {
					ed[e.ind] = -X;
					continue;
				}
				ind++;
				ed[e.ind] = ind;
				graph[X].push_back({ ind,X,Y,e.d });
			}
		}
	}
};

ll N;
vll x;
vll y;

vll pos;
vll verx, very;


ll H = 15;
ll M = 1 << H;

void dr(ll v, ll a, ll b, ll l, ll r, ll k, vector<vector<edge>> &g) {
	if (b <= l || a >= r) { return; }
	if (a <= l && b >= r) { g[v].push_back({ 1,v,k,1 }); return; }

	dr(v, a, b, l, (l + r) / 2, 2 * k, g);
	dr(v, a, b, (l + r) / 2, r, 2 * k + 1, g);
}

bool ch(ll d) {
	
	vector<vector<edge>> g(2 * M);
	repn(v, M - 1) {
		g[v].push_back({ 1,v,2 * v,1 });
		g[v].push_back({ 1,v,2 * v + 1,1 });
	}

	rep(i, N) {
		ll v = verx[i];
		auto itr = upper_bound(pos.begin(), pos.end(), y[i] - d);
		ll a = distance(pos.begin(), itr);
		auto itr2 = lower_bound(pos.begin(), pos.end(), y[i] + d);
		ll b = distance(pos.begin(), itr2);
		dr(v+M, a, very[i], 0, M, 1, g);
		dr(v + M, very[i]+1, b, 0, M, 1, g);

	}
	rep(i, N) {
		ll v = very[i];
		auto itr = upper_bound(pos.begin(), pos.end(), x[i] - d);
		ll a = distance(pos.begin(), itr);
		auto itr2 = lower_bound(pos.begin(), pos.end(), x[i] + d);
		ll b = distance(pos.begin(), itr2);

		dr(v+M, a, verx[i], 0, M, 1, g);
		dr(v + M, verx[i]+1, b, 0, M, 1, g);

	}

	//repn(v, 2 * M-1) {
	//	for (edge e : g[v]) {
	//		cout << v << " " << e.to << endl;
	//	}
	//}

	SCC sc(g);

	rep(i, N) {
		if (sc.ver[verx[i]+M] == sc.ver[very[i]+M]) { return false; }
	}
	return true;

	
}


int main() {
	cin >> N;
	x.resize(N);
	y.resize(N);
	rep(i, N)cin >> x[i] >> y[i];

	vector<pair<ll, ll>> p(2 * N);
	rep(i, N) {
		p[i] = { x[i],i };
		p[N + i] = { y[i],N + i };
	}
	sort(p.begin(), p.end());

	pos.resize(2 * N);
	verx.resize(N);
	very.resize(N);

	rep(i, 2*N) {
		if (p[i].second < N) { verx[p[i].second] = i; }
		else { very[p[i].second - N] = i; }
		pos[i] = p[i].first;
		//cout << pos[i] << endl;
	}

	ll l = 0;
	ll r = 1500000000;

	while (r - l > 1) {
		ll m = (r + l) / 2;
		if (ch(m)) { l = m; }
		else { r = m; }
	}
	cout << l << endl;

	
}


Measured memory_bytes: 144084