// Slower C++ solution:
//周♂雨扬是最强的！！！

//大佬祝您AK

//沈哲♂贝是最强的！！！

/*#include<iostream>

#include<algorithm>

#include<cmath>

#include<cstring>

#include<fstream>

using namespace std;

int n,m;

int a[403][403];

int point[403],vis[403],tong[403];

inline bool pd(int x){

	while(1){

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

			int j=point[i];

			while(j<=m){

				if(vis[a[i][j]]){

					j++;

				}else{

					point[i]=j;

					tong[a[i][j]]++;

					break;

				}

			}

			if(j==m+1){

				return 0;

			}

		}

		bool yes=false;

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

			if(tong[i]>x){

				yes=true;

				vis[i]=1;

			}

			tong[i]=0;

		}

		if(yes==false){

			return 1;

		}

	}

	return 1;

}

int main(){

	cin>>n>>m;

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

		for(int j=1;j<=m;j++){

			cin>>a[i][j];

		}

	}

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

		vis[i]=0;

	}

	int ans=m;

	for(int k=1;k<=m;k++){

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

			tong[i]=0;

		}

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

			int j=point[i];

			while(j<=m){

				if(vis[a[i][j]]){

					j++;

				}else{

					point[i]=j;

					tong[a[i][j]]++;

					break;

				}

			}

			if(j>=m+1){

				break;

			}

		}

		int nowans=0,now;

		bool yes=false;

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

			if(tong[i]>nowans&&!vis[i]){

				now=i;

				nowans=tong[i];

			}

		}

		cout<<nowans<<endl;

		vis[now]=1;

		ans=min(ans,nowans);

	}

	cout<<ans<<endl;

	int l=1,r=m;

	while(l<r){

		int mid=(l+r)/2;

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

			point[i]=1;

		}

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

			vis[i]=0;

		}

		if(pd(mid)){

			r=mid;

		}else{

			l=mid+1;

		}

	}

	bool yes=false;

	if(pd(r)){

		yes=true;

		cout<<r<<endl;

	}else{

		yes=true;

		cout<<l<<endl;

	}

	if(yes==false){

		cout<<m<<endl;

	}

	return 0;

}



in:

4 5

5 1 3 4 2

2 5 3 1 4

2 3 1 4 5

2 5 4 3 1

out:

2



in:

3 3

2 1 3

2 1 3

2 1 3

out:

3



*/

//沈♂哲贝是最强的！！！

//大佬祝您AK

//周♂雨扬是最强的！！！

#include<string.h>

#include<iostream>

#include<math.h>

#include<algorithm>

using namespace std;

int a[303][303],point[303],tong[303];

int n,m,ans;

bool vis[303],yes;

int main(){

	cin>>n>>m;

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

		for(int j=1;j<=m;j++){

			cin>>a[i][j];

		}

	}

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

		point[i]=1;

		tong[a[i][1]]++;

	}

	yes=1,ans=1e9;

	while(yes){

		int k=0;

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

			if(tong[i]>tong[k]){

				k=i;

			}

		}

		ans=min(ans,tong[k]);

		vis[k]=1;

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

			while(vis[a[i][point[i]]]){

				tong[a[i][point[i]]]--;

				point[i]++;

				tong[a[i][point[i]]]++;

			}

			if(point[i]!=m+1){

				yes&=true;

			}else{

				yes&=false;

			}

		}

	}

	cout<<ans<<endl;

	return 0;

}

/*



in:

4 5

5 1 3 4 2

2 5 3 1 4

2 3 1 4 5

2 5 4 3 1

out:

2



in:

3 3

2 1 3

2 1 3

2 1 3

out:

3



*/

// Faster C++ solution for the same problem (measured speedup: 5.184689081601115x):
#include<stdio.h>

#include<cstring>

#include<algorithm>

using namespace std;

#define N 305



int n,m,i,j,l,r,mid,Max,ans;

int a[N][N],num[N],pos[N];

bool vis[N];



void get(){Max=0;

	for(int i=1;i<=m;i++)

		if(num[i]>num[Max])Max=i;

}

bool check1(int x){

	memset(num,0,sizeof(num));

	memset(vis,0,sizeof(vis));

	for(int i=1;i<=n;i++)num[a[i][1]]++,pos[i]=1;

	while(get(),num[Max]>x){

		num[Max]=0;vis[Max]=1;

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

			if(a[i][pos[i]]==Max){

				while(vis[a[i][pos[i]]]&&pos[i]<=m)pos[i]++;

				if(pos[i]>m)return 0;

				num[a[i][pos[i]]]++;

			}

	}return 1;

}

int main()

{

	scanf("%d%d",&n,&m);

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

	for(j=1;j<=m;j++)

		scanf("%d",&a[i][j]);

	l=1,r=n;

	while(l<=r){

		mid=(l+r)>>1;

		if(check1(mid))ans=mid,r=mid-1;

			else l=mid+1;

	}printf("%d\n",ans);

	return 0;

}