7 20
4 6
6 7
4 5
1 2
2 4
1 7
3 5
2 1
6 2
6 1
7 3
3 2
3 6
3 1
3 4
2 5
1 6
7 4
6 3
7 5
 8 23
1 2
1 4
1 6
1 8
2 3
2 4
2 5
2 6
2 7
2 8
3 4
3 5
3 6
3 7
3 8
4 5
4 6
4 7
5 6
5 7
5 8
6 8
7 8
 4 4
2 1
3 1
1 4
3 2
 8 18
1 4
1 6
1 7
2 3
2 4
2 5
2 6
2 7
2 8
3 4
3 8
4 7
5 6
5 7
5 8
6 7
6 8
7 8
 10 34
7 10
2 3
2 4
2 5
9 10
2 7
2 8
2 10
4 5
4 6
4 7
4 8
4 9
6 7
6 8
6 9
6 10
1 2
1 3
1 5
8 9
1 6
1 7
1 8
1 9
1 10
3 4
3 5
3 6
3 8
3 10
5 6
5 9
5 10
 5 7
1 2
2 3
3 4
1 5
2 5
3 5
4 5
 2 0
 8 23
2 7
7 5
8 6
8 2
6 3
3 5
8 1
8 4
8 3
3 4
1 2
2 6
5 2
6 4
7 6
6 5
7 8
7 1
5 4
3 7
1 4
3 1
3 2
 2 1
1 2
 6 9
1 2
1 4
1 5
2 3
2 5
2 6
3 5
4 6
5 6
 12 56
9 5
2 6
9 8
5 4
1 11
1 6
4 1
1 10
10 3
8 4
5 1
9 1
5 10
2 7
11 5
6 11
5 8
7 6
3 2
12 7
8 6
12 3
1 2
8 1
2 11
10 12
4 6
5 12
2 4
10 2
7 3
12 11
7 10
7 1
9 2
11 9
9 10
8 7
11 3
7 9
5 7
4 12
3 5
12 2
4 10
9 12
5 2
9 4
11 8
8 2
3 6
4 11
8 10
6 10
3 9
3 4
 12 58
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 10
1 11
1 12
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 12
3 4
3 5
3 6
3 7
3 8
3 9
3 10
3 11
3 12
4 5
4 6
4 8
4 11
4 12
5 6
5 7
5 8
5 9
5 10
5 11
6 7
6 8
6 9
6 10
6 11
6 12
7 8
7 9
7 10
7 11
7 12
8 9
8 10
8 11
9 10
9 11
9 12
10 12
 4 3
2 1
3 1
4 2
 3 1
2 3
 6 10
1 2
1 3
1 4
1 6
2 3
2 4
2 5
3 5
3 6
4 6
 11 49
10 3
6 4
11 3
7 6
10 6
6 1
4 3
10 2
4 5
9 2
10 1
5 7
1 5
9 7
2 11
8 6
3 9
2 5
9 5
6 5
1 4
11 9
1 7
8 10
3 6
3 7
11 5
6 9
4 10
8 7
4 9
8 2
4 2
8 11
7 4
9 10
8 1
10 7
3 2
5 8
8 9
1 3
2 7
10 11
5 3
10 5
4 11
1 11
8 3
 5 4
1 4
2 3
4 3
4 2
 4 3
1 2
3 1
4 3
 4 3
1 3
1 4
2 3
 10 36
7 8
7 9
2 3
2 4
2 5
9 10
2 7
2 8
2 9
2 10
4 5
4 6
4 7
4 8
4 10
6 7
6 9
6 10
1 2
1 3
1 4
8 9
1 5
8 10
1 7
1 8
1 9
1 10
3 4
3 6
3 7
3 9
5 6
5 7
5 9
5 10
 8 15
2 1
4 5
2 4
3 4
2 5
3 5
2 6
3 6
5 6
4 6
2 7
3 8
2 8
3 7
6 7

3
1 2 4 
 3
1 2 5 
 2
1 3 
 1
8 
 1
10 
 2
1 4 
 1
2 
 3
1 3 4 
 2
1 1 
 1
6 
 3
1 4 7 
 4
1 1 1 9 
 1
4 
 1
3 
 1
6 
 5
1 1 1 2 6 
 1
5 
 1
4 
 1
4 
 2
2 8 
 1
8 

/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author
 */


#ifndef SOLUTION_COMMON_H

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using Pii = pair<int, int>;
template<typename T> using V = vector<T>;
using Vi = V<int>;
#define _1 first
#define _2 second
#define all(x) x.begin(), x.end()
#define pb push_back
#define lb lower_bound
#define amax(a, b) a = max(a, b)
#define amin(a, b) a = min(a, b)
#define tmax(_next, _prev, expr) if (_prev != INF) { auto prev = _prev; amax(_next, expr); }
#define tmin(_next, _prev, expr) if (_prev != INF) { auto prev = _prev; amin(_next, expr); }
#define dim2(a, b, init) vector(a, vector(b, init))
#define dim3(a, b, c, init) vector(a, vector(b, vector(c, init)))
#define dim4(a, b, c, d, init) vector(a, vector(b, vector(c, vector(d, init))))

#ifndef M_PI
static const double M_PI = acos(-1.0);
#endif

#ifdef MY_DEBUG
# define DEBUG(x) x
const bool isDebug = true;
#else
# define DEBUG(x)
const bool isDebug = false;
#endif

template<class A, class B>
std::ostream & operator <<(ostream &os, const pair<A, B> &p) {
  os << "(" << p._1 << "," << p._2 << ")";
  return os;
}

void __print(int x) {cerr << x;}
void __print(long x) {cerr << x;}
void __print(long long x) {cerr << x;}
void __print(unsigned x) {cerr << x;}
void __print(unsigned long x) {cerr << x;}
void __print(unsigned long long x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}
void __print(V<bool> x) {for (auto i : x) cerr << i;}

template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '('; __print(x.first); cerr << ','; __print(x.second); cerr << ')';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto const &i: x) cerr << (f++ ? "," : ""), __print(i); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef MY_DEBUG
#define debug(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define debug(x...)
#endif


template<class T>
string join(V<T> &A, string delimiter = " ") {
  ostringstream os;
  for (int i = 0; i < A.size(); ++i) {
    if (i > 0) os << delimiter;
    os << A[i];
  }
  return os.str();
}

template <typename T>
istream& operator>>(istream& in, vector<T> &A) {
  for (int i = 0; i < A.size(); i++) {
    in >> A[i];
  }
  return in;
}

template <typename T = int>
tuple<V<T>, V<T>> na2(istream& in, int N, int add = 0) {
  auto res = make_tuple(V<T>(N), V<T>(N));
  for (int i = 0; i < N; ++i) {
    in >> get<0>(res)[i] >> get<1>(res)[i];
    get<0>(res)[i] += add;
    get<1>(res)[i] += add;
  }
  return res;
}


template <typename T = int>
V<V<T>> nm(istream& in, int N, int M, int add = 0) {
  auto res = dim2(N, M, 0);
  for (int i = 0; i < N; ++i) {
    in >> res[i];
    if (add) {
      for (auto &a : res[i]) {
        a += add;
      }
    }
  }
  return res;
}

template <typename T>
inline T floorDiv(T num, T d) {
  if (num >= 0) {
    return num / d;
  } else {
    T res = num / d;
    if (num % d) --res;
    return res;
  }
}

template<typename T>
inline T min2(T a, T b) {
  return min(a, b);
}
template<typename T>
inline T max2(T a, T b) {
  return max(a, b);
}


#define SOLUTION_COMMON_H

#endif //SOLUTION_COMMON_H


V<Vi> buildUGraph(int N, Vi &from, Vi &to) {
  V<Vi> g(N);
  for (int i = 0; i < from.size(); ++i) {
    g[from[i]].pb(to[i]);
    g[to[i]].pb(from[i]);
  }
  return g;
}

/**
 * 隣接行列使うようになっているので、隣接リストバージョンが欲しい
 */
bool topological_sort(const V<Vi> &g, Vi &res) {
  Vi deg(g.size(), 0);
  for (auto & v : g) {
    for (int j = 0; j < v.size(); ++j) {
      if (v[j]) deg[j]++;
    }
  }

  deque<int> q;
  for (int i = 0; i < g.size(); ++i) {
    if (deg[i] == 0) q.push_back(i);
  }

  while(!q.empty()) {
    int v = q.front();
    q.pop_front();
    res.push_back(v);

    for (int u = 0; u < g[v].size(); ++u) {
      if (g[v][u]) {
        deg[u]--;
        if (deg[u] == 0) q.push_back(u);
      }
    }
  }

  bool ok = true;
  for (const auto &d : deg) ok &= d == 0;
  return ok;
}

/*
 * g: (node, cost)形式の隣接リスト
 */
V<ll> dijkstra(const V<V<Pii>> &g, int src) {
  using E = pair<ll, int>; // (cost, node)
  ll INF = (ll)1e18;
  int n = (int)g.size();
  V<ll> d(n, INF);
  priority_queue<E, V<E>, greater<>> q;
  q.push(E(0, src));
  d[src] = 0;

  while(!q.empty()) {
    auto visit = q.top();
    q.pop();
    int v = visit._2;
    ll c = visit._1;

    if (d[v] == c) {
      d[v] = c;
      for (const auto &e : g[v]) {
        if (d[e._1] > c + e._2) {
          q.push(E(c + e._2, e._1));
          d[e._1] = c + e._2;
        }
      }
    }
  }

  return d;
}

/*
 * 最大でK回遷移する
 */
int kth_bellman_ford(V<V<Pii>> &g, int src, int dst, int K) {
  int INF = (int)1e9;
  int n = (int)g.size();
  V<Vi> d(K + 1, Vi(n, INF));
  d[0][src] = 0;
  for (int k = 0; k < K; ++k) {
    for (int v = 0; v < n; ++v) {
      for (const auto &u : g[v]) {
        d[k + 1][u._1] = min(d[k + 1][u._1], d[k][v] + u._2);
      }
    }
  }

  int res = INF;
  for (int k = 1; k <= K; ++k) res = min(res, d[k][dst]);
  return res == INF ? -1 : res;
}


class UnionFind {
public:
  Vi p;
  Vi rank;

  UnionFind(int n): p(n), rank(n, 1) {
    for (int i = 0; i < n; ++i) {
      p[i] = i;
    }
  }

  int unite(int x, int y) {
    int idx = find(x), idy = find(y);
    if (idx == idy) return idx;

    auto merge = [&](int nd, int rt) {
      rank[rt] += rank[nd];
      p[nd] = rt;
      return rt;
    };

    return rank[idx] < rank[idy] ? merge(idx, idy) : merge(idy, idx);
  }

  int find(int x) {
    return p[x] == x ? x : find(p[x]);
  }

  bool same(int x, int y) {
    return find(x) == find(y);
  }

  bool isRoot(int x) {
    return find(x) == x;
  }

  int countConnected(int x) {
    return rank[find(x)];
  }
};



// あえて型固定。Viが渡ってきてもllで返すのでoverflowしない
template <typename T>
ll sumOf(V<T> &A) {
  ll s = 0;
  for (int i : A) s += i;
  return s;
}

V<ll> cum_sum(Vi &A) {
  V<ll> res(A.size() + 1);
  res[0] = 0;
  for (int i = 0; i < A.size(); ++i) {
    res[i + 1] = res[i] + A[i];
  }
  return res;
}

template <typename T>
T maxOf(V<T> &A) {
  return *std::max_element(all(A));
}

template <typename T>
T minOf(V<T> &A) {
  return *std::min_element(all(A));
}

void remove(Vi &A, int x) {
  A.erase(std::remove(all(A), x), A.end());
}

/**
 * multisetのキーをiterateする方法
 */
void unique(std::multiset<int> &A, const function<void(int)>& f) {
  for (auto it = A.begin(); it != A.end(); it = std::upper_bound(it, A.end(), *it)) {
    f(*it);
  }
}

inline bool within(int a, int until, int from = 0) {
  return from <= a && a < until;
}

const int MOD = 1000000007;
//#include "../library/MInt.hpp"
//using mint = MInt<MOD>;

struct Solve {
  int N, M;
  V<set<int>> g;
  V<bool> visited;
  V<bool> big;

  Solve(int n, int m, const V<set<int>> &g) : N(n), M(m), g(g), visited(n), big(n) {}

  bool testLimit(int maybeConnected) {
    return ll(maybeConnected)*(N - maybeConnected) <= M;
  }

  int findConnected(int s) {
    set<int> connected;

    function<bool(int)> dfs = [&](int u) {
      visited[u] = true;
      if (!testLimit(N - g[u].size())) return false;
      connected.insert(u);
      for (int v = 0; v < N; ++v) {
        if (v == u) continue;
        if (g[u].count(v)) continue;
        if (big[v]) return false;
        connected.insert(v);
        if (!testLimit(connected.size())) return false;
        if (!visited[v]) {
          if (!dfs(v)) return false;
        }
      }
      return true;
    };

    if (dfs(s)) {
      return connected.size();
    }
    else {
      for (const auto &i : connected) {
        big[i] = true;
      }
      return -1;
    }
  }

  Vi solve() {
    Vi ans;
    for (int i = 0; i < N; ++i) {
      if (visited[i]) continue;
      int size = findConnected(i);
      if (size > 0) ans.pb(size);
    }
    ll remain = N - sumOf(ans);
    if (remain > 0) ans.pb(remain);
    return ans;
  }
};

class EConnectedComponents {
public:
  void solve(std::istream& in, std::ostream& out) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M;
    in >> N >> M;
    int MAX = isDebug ? 1 : 5000;
    auto [from, to] = na2(in, M, -1);
    if (N <= MAX) {
      auto g = dim2(N, N, true);
      for (int i = 0; i < M; ++i) {
        g[from[i]][to[i]] = false;
        g[to[i]][from[i]] = false;
      }
      UnionFind uf(N);
      for (int i = 0; i < N; ++i) {
        for (int j = i + 1; j < N; ++j) {
          if (g[i][j]) uf.unite(i, j);
        }
      }
      Vi ans;
      for (int i = 0; i < N; ++i) {
        if (uf.isRoot(i)) ans.pb(uf.countConnected(i));
      }
      printAns(out, ans);
    }
    else {
      V<set<int>> g(N);
      for (int i = 0; i < M; ++i) {
        g[from[i]].insert(to[i]);
        g[to[i]].insert(from[i]);
      }
      Solve solve(N, M, g);
      auto ans = solve.solve();
      printAns(out, ans);
    }
  }

  void printAns(ostream &out, Vi &ans) const {
    sort(all(ans));
    out << ans.size() << endl;
    out << join(ans) << endl;
  }
};

int main() {
	EConnectedComponents solver;
	std::istream& in(std::cin);
	std::ostream& out(std::cout);
	solver.solve(in, out);
	return 0;
}
