#ifndef LOCAL
#define NDEBUG 1
#endif
#include<bits/stdc++.h>

std::vector<std::array<int, 2>> pos;
struct Item{
	int index, pos;
	bool operator<(Item other) const{return pos<other.pos;}
};
std::vector<Item> posSorted;

std::vector<std::vector<int>> add;
// edge x->y: condition x implies condition y
// condition x = !(condition x xor 1)

std::vector<char> state; // in computePostorder: 0 unvisited, 1 visited
// in solve (find 2SAT solution): -1 unvisited, 0|1 value

std::vector<int> postorder;
void computePostorder(int node){
	state[node]=-1;
	for(auto other: add[node]) if(state[other]==0){
		computePostorder(other);
	}
	postorder.push_back(node);
}

struct Invalid{};
void solve(int node){
	assert(state[node]==-1);
	assert(state[node xor 1]==-1);
	state[node]=1; state[node xor 1]=0;
	for(auto other: add[node]) if(state[other]==-1){
		solve(other);
	}else if(state[other]==0){
		throw Invalid{};
	}
}

bool existsSolution(int minGap){
	assert(minGap>0);

	add.resize(pos.size()*10);
	for(auto & it: add) it.clear();
	auto const number=(int)pos.size();
	// add[i*2+j]: pos[i][j] used

	auto const prefixNode=[&](int index)->int{
		assert(0<=index); assert(index<number*2);
		return (number+index)*2+1;
	};
	auto const suffixNode=[&](int index)->int{
		assert(0<=index); assert(index<number*2);
		return (number*3+index)*2+1;
	};

	auto const imply=[&](int first, int sec){
		add[first].push_back(sec); add[sec xor 1].push_back(first xor 1);
	};

	for(int index=0; index<number*2; ++index){
		imply(posSorted[index].index, prefixNode(index));
		if(index!=0 and posSorted[index].pos/minGap==posSorted[index-1].pos/minGap)
			imply(prefixNode(index-1), prefixNode(index));
	}
	for(int index=number*2; index--;){ // connect or-suffix nodes
		imply(posSorted[index].index, suffixNode(index));
		if(index!=number*2-1 and posSorted[index].pos/minGap==posSorted[index+1].pos/minGap)
			imply(suffixNode(index+1), suffixNode(index));
	}
	for(int index=number*2, last=number*2-1; index--;){ // connect conditions
		while(posSorted[last].pos-posSorted[index].pos>=minGap) --last;

		// if index is true, then range ]index..last] must be false
		if(last==index) continue;
		assert(last>index);
		bool c1, c2;
		if((c1=posSorted[index+1].pos/minGap==posSorted[index].pos/minGap))
			imply(suffixNode(index+1), posSorted[index].index xor 1);
		if((c2=posSorted[last].pos/minGap!=posSorted[index].pos/minGap)){
			assert(posSorted[last].pos/minGap==posSorted[index].pos/minGap+1);
			imply(prefixNode(last), posSorted[index].index xor 1);
		}
		assert(c1 or c2);
	}
	
	

	postorder.clear(); postorder.reserve(add.size());
	state.assign(add.size(), 0);
	for(int node=0; node<(int)add.size(); ++node)
		if(state[node]==0) computePostorder(node);
	assert(postorder.size()==add.size());

	try{
		std::for_each(postorder.rbegin(), postorder.rend(),[&](auto node){
			if(state[node]<0)
				solve(node xor 1);
		});
		return true;
	}catch(Invalid){
		return false;
	}
}

int main(){
	std::ios::sync_with_stdio(0);std::cin.tie(0);
	int number; std::cin>>number;
	pos.resize(number);
	for(int index=0; index<number; ++index)
		for(int choice=0; choice<2; ++choice){
			std::cin>>pos[index][choice];
			posSorted.push_back({index*2+choice, pos[index][choice]});
		}
	std::sort(begin(posSorted), end(posSorted));

	int result=0;
	for(int step=1<<30; step; step>>=1) if(existsSolution(result+step)) result+=step;
	std::cout<<result<<'\n';
}


Measured memory_bytes: 11260