// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;



typedef long long ll;

typedef long double ld;

typedef double db;

typedef string str;



typedef pair<int, int> pi;

typedef pair<ll, ll> pl;

typedef pair<db, db> pd;



typedef vector<int> vi;

typedef vector<ll> vl;

typedef vector<db> vd;

typedef vector<char> vc;

typedef vector<bool> vb;

typedef vector<str> vs;

typedef vector<pi> vpi;

typedef vector<pl> vpl;

typedef vector<pd> vpd;

typedef vector<vi> vii;

typedef vector<vl> vll;

typedef vector<vd> vdb;

typedef vector<vb> vbb;

typedef vector<vc> vcc;

typedef vector<vs> vss;



#define f first

#define s second	

#define sz(x) (int)(x).size()

#define all(x) (x).begin(), (x).end()

#define rall(x) (x).rbegin(), (x).rend()

#define part(x, n) (x).begin(), (x).begin()+n

#define rpart(x, n) (x).rbegin(), (x).rbegin()+n

#define rsz resize

#define ins insert

#define cnt count

#define fr front()

#define bk back()

#define pf push_front

#define pb push_back

#define eb emplace_back

#define lb lower_bound

#define ub upper_bound



#define LSOne(S) ((S)&-(S))



#define F0R(i, a, b) for(int i = (a); i < (b); ++i)

#define FOR(i, a) F0R(i, 0, a)

#define R0F(i, a, b) for(int i = (b)-1; i >= (a); --i)

#define ROF(i, a) R0F (i, 0, a)

#define trav(a, x) for (auto& a: x)



const int MOD = 1e9+7;



//input

template<class A> void read(complex<A>& c);

template<class A, class B> void read(pair<A,B>& p);

template<class A> void read(vector<A>& v);

template<class A, size_t SZ> void read(array<A,SZ>& a);



template<class T> void read(T& x) { cin >> x; }

void read(db& d) { str t; read(t); d = stod(t); }

void read(ld& d) { str t; read(t); d = stold(t); }

template<class H, class... T> void read(H& h, T&... t) { read(h); read(t...); }



template<class A> void read(complex<A>& c) { A a,b; read(a,b); c = {a,b}; }

template<class A, class B> void read(pair<A,B>& p) { read(p.f,p.s); }

template<class A> void read(vector<A>& x) { trav(a,x) read(a); }

template<class A, size_t SZ> void read(array<A,SZ>& x) { trav(a,x) read(a); }



//output

template<class A> void print(A x) { cout << (x); }

template<class H, class... T> void print(const H& h, const T&... t) {

	print(h); print(t...); }

void prints() { print("\n"); } // print w/ spaces

template<class H, class... T> void prints(const H& h, const T&... t) {

	print(h); if (sizeof...(t)) print(" "); prints(t...); }



void setIn(str s) {freopen(s.c_str(), "r", stdin);}

void setOut(str s) { freopen(s.c_str(), "w", stdout);}

void unsyncIO() { ios::sync_with_stdio(0); cin.tie(0);}

void setIO(str s= ""){

	unsyncIO();

	if(sz(s)) { setIn(s+".in"), setOut(s+".out");}

}



const int mxN = 2e5;

vii adj(mxN), cc;

vb vis(mxN);

vi cur;

int n, m;



void dfs(int u){

	vis[u] = 1;

	cur.pb(u);

	trav(v, adj[u])

		if(!vis[v])

			dfs(v);

}

int main(){

	setIO();

	read(n, m);

	int u, v;

	FOR(i, m){

		read(u, v);

		u--, v--;

		adj[u].pb(v);

		adj[v].pb(u);

	}

	FOR(i, n)

		if(!vis[i]){

			cur.clear();

			dfs(i);

			cc.pb(cur);

		}

	int ans = 0;

	FOR(i, sz(cc))

		ans = max(sz(cc[i]), ans);

	prints(ans);

	return 0;

}




// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;



typedef long long ll;

typedef long double ld;

typedef double db;

typedef string str;



typedef pair<int, int> pi;

typedef pair<ll, ll> pl;

typedef pair<db, db> pd;



typedef vector<int> vi;

typedef vector<ll> vl;

typedef vector<db> vd;

typedef vector<char> vc;

typedef vector<bool> vb;

typedef vector<str> vs;

typedef vector<pi> vpi;

typedef vector<pl> vpl;

typedef vector<pd> vpd;

typedef vector<vi> vii;

typedef vector<vl> vll;

typedef vector<vd> vdb;

typedef vector<vb> vbb;

typedef vector<vc> vcc;

typedef vector<vs> vss;



#define f first

#define s second	

#define sz(x) (int)(x).size()

#define all(x) (x).begin(), (x).end()

#define rall(x) (x).rbegin(), (x).rend()

#define part(x, n) (x).begin(), (x).begin()+n

#define rpart(x, n) (x).rbegin(), (x).rbegin()+n

#define rsz readsize

#define ins insert

#define cnt count

#define ft front()

#define bk back()

#define pf push_front

#define pb push_back

#define eb emplace_back

#define lb lower_bound

#define ub upper_bound



#define LSOne(S) ((S)&-(S))



#define F0R(i, a, b) for(int i = (a); i < (b); ++i)

#define FOR(i, a) F0R(i, 0, a)

#define R0F(i, a, b) for(int i = (b)-1; i >= (a); --i)

#define ROF(i, a) R0F (i, 0, a)

#define trav(a, x) for (auto& a: x)



const int MOD = 1e9+7;



//input

template<class A> void read(complex<A>& c);

template<class A, class B> void read(pair<A,B>& p);

template<class A> void read(vector<A>& v);

template<class A, size_t SZ> void read(array<A,SZ>& a);



template<class T> void read(T& x) { cin >> x; }

void read(db& d) { str t; read(t); d = stod(t); }

void read(ld& d) { str t; read(t); d = stold(t); }

template<class H, class... T> void read(H& h, T&... t) { read(h); read(t...); }



template<class A> void read(complex<A>& c) { A a,b; read(a,b); c = {a,b}; }

template<class A, class B> void read(pair<A,B>& p) { read(p.f,p.s); }

template<class A> void read(vector<A>& x) { trav(a,x) read(a); }

template<class A, size_t SZ> void read(array<A,SZ>& x) { trav(a,x) read(a); }



//output

template<class A> void print(A x) { cout << (x); }

template<class H, class... T> void print(const H& h, const T&... t) {

	print(h); print(t...); }

void prints() { print("\n"); } // print w/ spaces

template<class H, class... T> void prints(const H& h, const T&... t) {

	print(h); if (sizeof...(t)) print(" "); prints(t...); }



void setIn(str s) {freopen(s.c_str(), "r", stdin);}

void setOut(str s) { freopen(s.c_str(), "w", stdout);}

void unsyncIO() { ios::sync_with_stdio(0); cin.tie(0);}

void setIO(str s= ""){

	unsyncIO();

	if(sz(s)) { setIn(s+".in"), setOut(s+".out");}

}



class UnionFind {

	private:

		vi p, rank, setSize;

		int numSets;

	public:

		UnionFind(int N){

			p.assign(N, 0);

			FOR(i, N)

				p[i]=i;

			rank.assign(N, 0);

			setSize.assign(N, 1);

			numSets = N;

		}

		int findSet(int i){

			return p[i]==i?i:p[i]=findSet(p[i]);

		}

		bool isSameSet(int i, int j){

			return findSet(i)==findSet(j);

		}

		int numDisjointSets(int i){

			return numSets;

		}

		int sizeOfSet(int i){

			return setSize[findSet(i)];

		}

		void unionSet(int i, int j){

			if(isSameSet(i, j))

				return;

			int x = findSet(i), y = findSet(j);

			if(rank[x]>rank[y])

				swap(x, y);

			p[x] = y;

			if(rank[x]==rank[y])

				++rank[y];

			setSize[y]+=setSize[x];

			--numSets;

		}

};



void solve(){

	int n, m, u, v;

	read(n, m);

	UnionFind ufds(n);

	FOR(i, m){

		read(u, v);

		u--, v--;

		ufds.unionSet(u, v);

	}

	int ans = 0;

	FOR(i, n)

		ans = max(ufds.sizeOfSet(i), ans);

	prints(ans);

}



int main(){

	setIO();

	int t=1;

	//read(t);

	while(t--)

		solve();

}




// Fastest known solution for this problem: