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

using namespace std;

class UF {

public:

    vector<int> fa;

    vector<int> sz;

    int n;

    int comp_cnt;



public:

    UF(int _n) : n(_n), comp_cnt(_n), fa(_n), sz(_n, 1) {

        iota(fa.begin(), fa.end(), 0);

    }



    int findset(int x) {

        return fa[x] == x ? x : fa[x] = findset(fa[x]);

    }



    void unite(int x, int y) {

        if (sz[x] < sz[y]) {

            swap(x, y);

        }

        fa[y] = x;

        sz[x] += sz[y];

        --comp_cnt;

    }



    bool findAndUnite(int x, int y) {

        int x0 = findset(x);

        int y0 = findset(y);

        if (x0 != y0) {

            unite(x0, y0);

            return true;

        }

        return false;

    }

};

int main() {

    int n, m;

    cin >> n >> m;

    UF uf(2e5 + 100);

    for (int i = 0; i < m; i++) {

        int a, b;

        cin >> a >> b;

        uf.findAndUnite(a, b);

    }

    int ans = 0;

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

        ans = max(ans, uf.sz[i]);

    }

    cout << ans << endl;

	return 0;

}

// Optimized solution to the same problem (faster):
#pragma region

#include <algorithm>

#include <cmath>

#include <cstring>

#include <iomanip>

#include <iostream>

#include <map>

#include <queue>

#include <set>

#include <stack>

#include <string>

#include <vector>

using namespace std;

typedef long long ll;

#define rep(i, a, n) for (int i = a; i <= n; ++i)

#define per(i, a, n) for (int i = n; i >= a; --i)

namespace fastIO {

#define BUF_SIZE 100000

#define OUT_SIZE 100000

//fread->R

bool IOerror = 0;

//inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}

inline char nc() {

    static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;

    if (p1 == pend) {

        p1 = buf;

        pend = buf + fread(buf, 1, BUF_SIZE, stdin);

        if (pend == p1) {

            IOerror = 1;

            return -1;

        }

    }

    return *p1++;

}

inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }

template <class T>

inline bool R(T &x) {

    bool sign = 0;

    char ch = nc();

    x = 0;

    for (; blank(ch); ch = nc())

        ;

    if (IOerror) return false;

    if (ch == '-') sign = 1, ch = nc();

    for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';

    if (sign) x = -x;

    return true;

}

inline bool R(double &x) {

    bool sign = 0;

    char ch = nc();

    x = 0;

    for (; blank(ch); ch = nc())

        ;

    if (IOerror) return false;

    if (ch == '-') sign = 1, ch = nc();

    for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';

    if (ch == '.') {

        double tmp = 1;

        ch = nc();

        for (; ch >= '0' && ch <= '9'; ch = nc())

            tmp /= 10.0, x += tmp * (ch - '0');

    }

    if (sign)

        x = -x;

    return true;

}

inline bool R(char *s) {

    char ch = nc();

    for (; blank(ch); ch = nc())

        ;

    if (IOerror)

        return false;

    for (; !blank(ch) && !IOerror; ch = nc())

        *s++ = ch;

    *s = 0;

    return true;

}

inline bool R(char &c) {

    c = nc();

    if (IOerror) {

        c = -1;

        return false;

    }

    return true;

}

template <class T, class... U>

bool R(T &h, U &... t) { return R(h) && R(t...); }

#undef OUT_SIZE

#undef BUF_SIZE

};  // namespace fastIO

using namespace fastIO;

template <class T>

void _W(const T &x) { cout << x; }

void _W(const int &x) { printf("%d", x); }

void _W(const int64_t &x) { printf("%lld", x); }

void _W(const double &x) { printf("%.16f", x); }

void _W(const char &x) { putchar(x); }

void _W(const char *x) { printf("%s", x); }

template <class T, class U>

void _W(const pair<T, U> &x) { _W(x.F), putchar(' '), _W(x.S); }

template <class T>

void _W(const vector<T> &x) {

    for (auto i = x.begin(); i != x.end(); _W(*i++))

        if (i != x.cbegin()) putchar(' ');

}

void W() {}

template <class T, class... U>

void W(const T &head, const U &... tail) { _W(head), putchar(sizeof...(tail) ? ' ' : '\n'), W(tail...); }

#pragma endregion

const int maxn = 2e5 + 5;

int fa[maxn];

int findroot(int x) { return x == fa[x] ? x : fa[x] = findroot(fa[x]); }

void link(int x, int y) { fa[findroot(x)] = findroot(y); }

int cnt[maxn];

int main() {

    int n, m;

    R(n, m);

    rep(i, 1, n) fa[i] = i;

    while (m--) {

        int x, y;

        R(x, y);

        link(x, y);

    }

    int ans = 0;

    rep(i, 1, n) cnt[findroot(i)]++, ans = max(ans, cnt[findroot(i)]);

    W(ans);

}

// Fastest known solution for this problem: