#include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define MT make_tuple
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second

#define DUMP(x) cout<<#x<<":"<<(x)<<endl
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class T>
istream& operator>>(istream& is, vector<T>& xs){
  for(auto& x: xs)
	is >> x;
  return is;
}
template<class S, class T>
ostream& operator<<(ostream& os, const pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
ostream& operator<<(ostream& os, const vector<T>& xs){
  for(unsigned int i=0;i<xs.size();++i)
	os << (i?" ":"") << xs[i];
  return os;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}


const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;

int H, W;
string vs[16];
bool ok_y[16];
bool same[16][16];
bool dfs2(const VI& match_y, bool init, int x, VI& match_x){
  if(x == W) return true;
  if(match_x[x] >= 0)
	return dfs2(match_y, init, x+1, match_x);

  for(int x1=x+1;x1<W;++x1){
	if(match_x[x1] >= 0) continue;
	bool ok = true;
	REP(y,H)
	  if(match_y[y] != H){
		if(vs[y][x] != vs[match_y[y]][x1]
		   || vs[y][x1] != vs[match_y[y]][x]){
		  ok = false;
		  break;
		}
	  }
	  else{
		if(vs[y][x] != vs[y][x1]){
		  ok = false;
		  break;
		}
	  }
	if(ok){
	  match_x[x] = x1;
	  match_x[x1] = x;
	  if(dfs2(match_y, init, x+1, match_x))
		return true;
	  match_x[x] = match_x[x1] = -1;
	}
  }
  if(init){
	bool ok = true;
	REP(y,H)
	  if(match_y[y] != H
		 && vs[y][x] != vs[match_y[y]][x]){
		ok = false;
		break;
	  }
	if(ok){
	  match_x[x] = W;
	  if(dfs2(match_y, false, x+1, match_x))
		return true;
	  match_x[x] = -1;
	}
  }
  
  return false;
}

bool dfs1(bool init, int y, VI& match){
  if(init){
	REP(y,H){
	  if(!ok_y[y]) continue;
	  match[y] = H;
	  if(dfs1(false, 0, match)){
		return true;
	  }
	  match[y] = -1;
	}
	return false;
  }

  if(y == H){
	VI match_x(W, -1);
	if(dfs2(match, W%2==1, 0, match_x))
	  return true;
	return false;
  }
  if(match[y] >= 0)
	return dfs1(init, y+1, match);

  for(int y1=y+1;y1<H;++y1)
	if(match[y1] < 0 && same[y][y1]){
	  match[y] = y1;
	  match[y1] = y;
	  if(dfs1(init, y+1, match))
		return true;
	  match[y] = match[y1] = -1;
	}
  return false;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  cin >> H >> W;
  REP(y,H) cin >> vs[y];

  REP(y,H){
  	set<char> s;
	for(char c: vs[y])
	  if(count(ALL(vs[y]), c) % 2)
		s.insert(c);
	ok_y[y] = SZ(s) <= 1;
  }

  if(H == 1){
	cout << (ok_y[0]? "YES": "NO") << endl;
	return 0;
  }

  REP(y,H) REP(y1,y+1){
	string s1 = vs[y];
	string s2 = vs[y1];
	SORT(s1);
	SORT(s2);
	if(s1 == s2)
	  same[y][y1] = same[y1][y] = true;
  }
  
  VI match(H, -1);
  cout << (dfs1(H%2==1, 0, match)? "YES": "NO") << endl;
	
  return 0;
}


Measured memory_bytes: 256