//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include
<map>
#include<stack>
#include<queue>
#include<cmath>
#include<fstream>
#include<algorithm>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,a,n) for(int i=n;i>=a;i--)
#define CLR(a) memset(a,0,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int maxn=1010;
int n,m;
char g[maxn][maxn];
int pre[maxn*2];
int ans[maxn*2];
int deg[maxn*2];
vector<int>edge[maxn*2];
void init(){
rep(i,1,n+m)pre[i]=i;
}
int Find(int x){
return x==pre[x]?x:pre[x]=Find(pre[x]);
}
void Union(int x,int y){
pre[Find(x)] = Find(y);
}
void toopsort(){
CLR(deg);
CLR(ans);
rep(i,1,n+m){
for(int j=0;j<edge[i].size();j++){
++deg[edge[i][j]];
}
}
queue<int>q;
rep(i,1,n+m){
//不用单独将连通块列出来,因为非缩的点不会有其余节点
//这里如果将i换成Find(i)反而会导致重复入队
if(deg[i]==0)q.push(i*10000+1),ans[i]=1;
}
while(!q.empty()){
int tmp=q.front();
q.pop();
int u = tmp/10000,step = tmp%10000;
for(int i=0;i<edge[u].size();i++){
if(--deg[edge[u][i]]==0)q.push(edge[u][i]*10000+step+1),ans[edge[u][i]]=step+1;
}
}
}
int main(){
scanf("%d %d", &n,&m);
init();
rep(i,1,n){
scanf("%s", g[i]+1);
rep(j,1,m){
if(g[i][j]=='='){
Union(i,n+j);
}
}
}
int flag=1;
rep(i,1,n){
rep(j,1,m){
if(Find(i)==Find(n+j)&&g[i][j]!='='){
flag=0;
break;
}
if(g[i][j]=='<')edge[Find(i)].push_back(Find(n+j)); if(g[i][j]=='>')edge[Find(n+j)].push_back(Find(i));
}
}
toopsort();
rep(i,1,n){
for(int j=0;j<edge[i].size();j++){ if(deg[edge[i][j]]>0){
flag=0;
break;
}
}
if(!flag)break;
}
if(!flag){
puts("No");
}else{
printf("Yes");
rep(i,1,n)printf(" %d", ans[Find(i)]);
printf(" ");
rep(i,1,m)printf(" %d", ans[Find(n+i)]);
}
return 0;
}