// Slower C++ solution:
#include <iostream>

#include <cstdio>

#include <cmath>

#include <string>

#include <cstring>

#include <algorithm>

#include <limits>

#include <vector>

#include <stack>

#include <queue>

#include <set>

#include <map>

#include <bitset>

#include <unordered_map>

#include <unordered_set>

#define lowbit(x) ( x&(-x) )

#define pi 3.141592653589793

#define e 2.718281828459045

#define INF 0x3f3f3f3f

#define HalF (l + r)>>1

#define lsn rt<<1

#define rsn rt<<1|1

#define Lson lsn, l, mid

#define Rson rsn, mid+1, r

#define QL Lson, ql, qr

#define QR Rson, ql, qr

#define myself rt, l, r

#define pii pair<int, int>

#define MP(a, b) make_pair(a, b)

using namespace std;

typedef unsigned long long ull;

typedef unsigned int uit;

typedef long long ll;

const int maxN = 1e4 + 7;

int N, a[maxN][2], _UP, l, r, lim, ans;

vector<int> same[maxN << 1];

pii lsan[maxN << 1];

namespace Graph

{

    const int maxP = (maxN << 3) + (maxN << 2);

    vector<int> E[maxP], NE[maxP];

    int root, tot, lc[maxP], rc[maxP];

    void build(int &rt, int fa, int l, int r)

    {

        rt = ++tot;

        if(fa) E[fa].push_back(rt);

        if(l == r) return;

        int mid = HalF;

        build(lc[rt], rt, l, mid);

        build(rc[rt], rt, mid + 1, r);

    }

    void Insert(int rt, int l, int r, int qx, int id)

    {

        if(l == r)

        {

            E[rt].push_back(id);

            return;

        }

        int mid = HalF;

        if(qx <= mid) Insert(lc[rt], l, mid, qx, id);

        else Insert(rc[rt], mid + 1, r, qx, id);

    }

    void update(int rt, int l, int r, int ql, int qr, int fid)

    {

        if(ql <= l && qr >= r)

        {

            NE[fid].push_back(rt);

            return;

        }

        int mid = HalF;

        if(qr <= mid) update(lc[rt], l, mid, ql, qr, fid);

        else if(ql > mid) update(rc[rt], mid + 1, r, ql, qr, fid);

        else { update(lc[rt], l, mid, ql, qr, fid); update(rc[rt], mid + 1, r, ql, qr, fid); }

    }

    int dfn[maxP], low[maxP], tim, Stap[maxP], Stop, Belong[maxP], Bcnt;

    bool instack[maxP];

    inline int another(int x) { return (x & 1) ? x + 1 : x - 1; }

    void Tarjan(int u)

    {

        dfn[u] = low[u] = ++tim;

        Stap[++Stop] = u;

        instack[u] = true;

        for(int v : E[u])

        {

            if(!dfn[v])

            {

                Tarjan(v);

                low[u] = min(low[u], low[v]);

            }

            else if(instack[v]) low[u] = min(low[u], dfn[v]);

        }

        for(int v : NE[u])

        {

            if(!dfn[v])

            {

                Tarjan(v);

                low[u] = min(low[u], low[v]);

            }

            else if(instack[v]) low[u] = min(low[u], dfn[v]);

        }

        if(u <= (N << 1))

        {

            int id = ceil(1. * u / 2), op = !(u & 1), val = a[id][op];

            for(int v : same[val])

            {

                if(another(v) == u) continue;

                if(!dfn[v])

                {

                    Tarjan(v);

                    low[u] = min(low[u], low[v]);

                }

                else if(instack[v]) low[u] = min(low[u], dfn[v]);

            }

        }

        if(dfn[u] == low[u])

        {

            Bcnt++;

            int v;

            do

            {

                v = Stap[Stop--];

                instack[v] = false;

                Belong[v] = Bcnt;

            } while(u ^ v);

        }

    }

    inline bool check()

    {

        for(int i=1; i<=tot; i++)

        {

            NE[i].clear();

            dfn[i] = 0;

            instack[i] = false;

        }

        for(int i=1, ql, qr; i<=N; i++)

        {

            ql = (int)(upper_bound(lsan + 1, lsan + _UP + 1, MP(lsan[a[i][0]].first - lim, INF)) - lsan);

            qr = (int)(lower_bound(lsan + 1, lsan + _UP + 1, MP(lsan[a[i][0]].first + lim, 0)) - lsan - 1);

            if(ql < a[i][0]) update(root, 1, _UP, ql, a[i][0] - 1, 2 * i - 1);

            if(qr > a[i][0]) update(root, 1, _UP, a[i][0] + 1, qr, 2 * i - 1);

            ql = (int)(upper_bound(lsan + 1, lsan + _UP + 1, MP(lsan[a[i][1]].first - lim, INF)) - lsan);

            qr = (int)(lower_bound(lsan + 1, lsan + _UP + 1, MP(lsan[a[i][1]].first + lim, 0)) - lsan - 1);

            if(ql < a[i][1]) update(root, 1, _UP, ql, a[i][1] - 1, 2 * i);

            if(qr > a[i][1]) update(root, 1, _UP, a[i][1] + 1, qr, 2 * i);

        }

        tim = Stop = Bcnt = 0;

        for(int i=1; i<=(N << 1); i++) if(!dfn[i]) Tarjan(i);

        for(int i=1; i<=(N << 1); i += 2)

        {

            if(Belong[i] == Belong[i + 1]) return false;

        }

        return true;

    }

    void G_init()

    {

        root = 0;

        tot = N << 1;

        build(root, 0, 1, _UP);

        for(int i=1; i<=N; i++)

        {

            Insert(root, 1, _UP, a[i][0], 2 * i);

            Insert(root, 1, _UP, a[i][1], 2 * i - 1);

        }

    }

};

using namespace Graph;

int main()

{

    scanf("%d", &N);

    _UP = 0;

    for(int i=1; i<=N; i++) { scanf("%d%d", &a[i][0], &a[i][1]); lsan[++_UP] = MP(a[i][0], i * 2 - 1); lsan[++_UP] = MP(a[i][1], i * 2); }

    sort(lsan + 1, lsan + _UP + 1);

    for(int i=1; i<=N; i++)

    {

        a[i][0] = (int)(lower_bound(lsan + 1, lsan + _UP + 1, MP(a[i][0], i * 2 - 1)) - lsan);

        same[a[i][0]].push_back(2 * i);

        a[i][1] = (int)(lower_bound(lsan + 1, lsan + _UP + 1, MP(a[i][1], i * 2)) - lsan);

        same[a[i][1]].push_back(2 * i - 1);

    }

    G_init();

    l = 1; r = 1e9;

    ans = 0;

    while(l <= r)

    {

        lim = HalF;

        if(check())

        {

            l = lim + 1;

            ans = lim;

        }

        else r = lim - 1;

    }

    printf("%d\n", ans);

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.188656561994028x):
#include <algorithm>

#include <iostream>

#include <cassert>

#include <cstring>

#include <utility>

#include <cstdio>

#include <cctype>

#include <vector>

using namespace std;



const int ALL=1e9+5;

const int MAXN=2e4+5;

const int MAXM=1e5+5;

vector<int> v[MAXM];



inline int read()

{

	int x=0;char ch=getchar();

	while(!isdigit(ch)) ch=getchar();

	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}

	return x;

}



inline void Min(int &x,int y)

{

	if(x>y) x=y;

}



int n,tot,another[MAXN],cnt[MAXN];

pair<int,int> dat[MAXN],rev[MAXN];



inline void prepare()

{

	sort(cnt+1,cnt+tot+1);

	sort(dat+1,dat+tot+1);

	for(int i=1;i<=tot;i++)

	{

		int id=dat[i].second;

		if(!rev[id].first)

			rev[id].first=i;

		else

			rev[id].second=i,

			another[i]=rev[id].first,

			another[rev[id].first]=i;

	}

}



namespace Segment_Tree

{

	int ls[MAXM],rs[MAXM],in[MAXM],out[MAXM],root,tree_cnt,to;

	

	void build(int l,int r,int &cur)

	{

		cur=++tree_cnt;

		if(l==r) return out[l]=cur,void();

		int mid=(l+r)>>1;

		build(l,mid,ls[cur]);

		build(mid+1,r,rs[cur]);

		v[cur].push_back(ls[cur]);

		v[cur].push_back(rs[cur]);

	}

	

	void modify(int l,int r,int ql,int qr,int cur)

	{

		if(ql<=l&&qr>=r)

			return v[to].push_back(cur);

		int mid=(l+r)>>1;

		if(ql<=mid) modify(l,mid,ql,qr,ls[cur]);

		if(qr>mid) modify(mid+1,r,ql,qr,rs[cur]);

	}

	

	inline void clear()

	{

		for(int i=1;i<=tree_cnt;i++)

			v[i].clear();

		tree_cnt=0;

	}

	

	inline void rebuild()

	{

		clear();

		for(int i=1;i<=tot;i++)

			in[i]=++tree_cnt;

		build(1,tot,root);

		for(int i=1;i<=tot;i++)

			v[out[i]].push_back(in[another[i]]);

	}

	

	inline void add(int cur,int l,int r)

	{

		to=cur; if(l>r) return;

		modify(1,tot,max(0,l),min(r,tot),root);

	}

	

	inline void add_edge(int mid)

	{

		for(int i=1;i<=tot;i++)

		{

			int pos=dat[i].first;

			int l=lower_bound(cnt+1,cnt+tot+1,pos-mid+1)-cnt;

			int r=upper_bound(cnt+1,cnt+tot+1,pos+mid-1)-cnt-1;

			add(in[i],l,i-1);

			add(in[i],i+1,r);

		}

	}

}



using Segment_Tree::in;

using Segment_Tree::out;

using Segment_Tree::tree_cnt;



namespace Tarjan

{

	int st[MAXM],top;

	int co[MAXM],co_cnt;

	int dfn[MAXM],low[MAXM],dfn_cnt;

	

	void tarjan(int x)

	{

		st[++top]=x;

		dfn[x]=low[x]=++dfn_cnt;

		for(auto y:v[x])

		{

			if(!dfn[y])

			{

				tarjan(y);

				Min(low[x],low[y]);

			}

			else if(!co[y])

				Min(low[x],dfn[y]);

		}

		if(dfn[x]==low[x])

		{

			++co_cnt;

			while(st[top]!=x)

				co[st[top--]]=co_cnt;

			co[st[top--]]=co_cnt;

		}

	}

	

	inline void clear()

	{

		top=co_cnt=dfn_cnt=0;

		memset(co,0,sizeof(co));

		memset(dfn,0,sizeof(dfn));

	}

	

	inline void tarjan()

	{

		clear();

		for(int i=1;i<=tree_cnt;i++)

			if(!dfn[i])

				tarjan(i);

	}

	

	inline bool check()

	{

		for(int i=1;i<=n;i++)

		{

			int x1=rev[i].first;

			int x2=rev[i].second;

			if(co[in[x1]]==co[out[x1]])

				return false;

			if(co[in[x2]]==co[out[x2]])

				return false;

		}

		return true;

	}

}



inline bool check(int mid)

{

	Segment_Tree::rebuild();

	Segment_Tree::add_edge(mid);

	Tarjan::tarjan();

	return Tarjan::check();

}



int main()

{

	n=read();

	for(int i=1;i<=n;i++)

	{

		int x=read(),y=read();

		cnt[++tot]=x,cnt[++tot]=y;

		dat[tot-1]=make_pair(x,i);

		dat[tot]=make_pair(y,i);

	}

	prepare();

	int l=0,r=ALL,ans=0;

	while(l<=r)

	{

		int mid=(l+r)>>1;

		if(!check(mid)) r=mid-1;

		else l=mid+1,ans=mid;

	}

	printf("%d\n",ans);

	return 0;

}