#include <bits/stdc++.h>

#include <boost/range/adaptors.hpp>
#include <boost/range/irange.hpp>

using namespace std;
using namespace boost;
using namespace boost::adaptors;

int main() {
    int64_t n, m;
    cin >> n >> m;

    vector<vector<int64_t>> a(n, vector<int64_t>(m));
    for (auto i : irange(0L, n)) {
        for (auto j : irange(0L, m)) {
            cin >> a[i][m - j - 1];
            --a[i][m - j - 1];
        }
    }

    int64_t ans = n;
    vector<bool> available(m, true);
    for (auto _ : irange(0L, m)) {
        vector<int64_t> c(m);

        for (const auto& b :
             a | transformed([](const auto& aa) { return aa.back(); })) {
            ++c[b];
        }

        auto b = max_element(c.begin(), c.end()) - c.begin();
        available[b] = false;
        ans = min(ans, c[b]);

        for (auto&& aa : a) {
            while (!aa.empty() && !available[aa.back()]) {
                aa.pop_back();
            }
        }
    }

    cout << ans << endl;
}

#include<bits/stdc++.h>
using namespace std;
const int N=305;
#define fi first
#define se second
typedef pair<int,int>P;
priority_queue<P>que;
int n,m,b[N],vi[N],cnt[N],a[N][N];
bool check(int mid){
	while(!que.empty())	que.pop();
	for(int i=1;i<=m;i++)	b[i]=0;
	for(int i=1;i<=n;i++)	++b[a[i][cnt[i]=1]];
	for(int i=1;i<=m;i++)	vi[i]=0,que.push(P(b[i],i));
	while(!que.empty()){
		P x=que.top();	que.pop();
		if(vi[x.se])	continue;
		if(x.fi<=mid)	return true;

		vi[x.se]=1;
		for(int i=1;i<=n;i++){
			if(a[i][cnt[i]]!=x.se)	continue;
			while(vi[a[i][cnt[i]]]&&cnt[i]<=m)	++cnt[i];
			if(cnt[i]>m)	return false;
			que.push(P(++b[a[i][cnt[i]]],a[i][cnt[i]]));
		}
	}
	return false;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	int l=1,r=n;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid))	r=mid;
		else	l=++mid;
	}
	printf("%d\n",l);
	return 0;
}
