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

class mdview {
    private:
        vector<int> *oda;
    public:
        mdview(vector<int> &oda) : oda(&oda) {}
        size_t size() const { return oda->size()/2; }
        int const *operator [](int idx) const { return oda->data() + idx*2; }
};

bool calc(vector<string> const &chars, mdview const &hgv, mdview const &wgv) {
    for (size_t hs = 0; hs < hgv.size(); hs++) {
        for (size_t ws = 0; ws < wgv.size(); ws++) {
            int y1 = hgv[hs][0];
            int x1 = wgv[ws][0];
            int y2 = hgv[hs][1];
            int x2 = wgv[ws][1];
            if (chars[y1][x1] != chars[y2][x2] || chars[y2][x1] != chars[y1][x2]) return false;
        }
    }
    return true;
}

pair<vector<int>,int> organize(vector<string> const &chars, vector<map<char, int>> const &cnt, int upto, bool is_h) {
    vector<int> gs(upto, -1);
    int g = 0;
    for (int i = 0; i < upto; i++) {
        bool exists = false;
        if (gs[i] != -1) continue;
        for (int j = i+1; j < upto; j++) {
            if (gs[j] != -1) continue;
            bool ok = cnt[i] == cnt[j];

            auto otpu = is_h ? chars[0].size() : chars.size();
            if (ok) for (int l = 0; l < j; l++) {
                if (l == i) continue;
                if (gs[l] != g) continue;
                bool same = true;
                for (size_t k = 0; k < otpu; k++) {
                    if (is_h) same = same && chars[l][k] == chars[j][k];
                    else      same = same && chars[k][l] == chars[k][j];
                }
                ok = ok && !same;
            }

            if (ok) {
                exists = true;
                gs[i] = gs[j] = g;
            }
        }
        if (exists) g++;
    }
    if (count(gs.begin(), gs.end(), -1) > 1) return make_pair(gs, -1);
    return make_pair(gs, g);
}

class groupings_generator {
    private:
        mdview curr;
        vector<int> curr_flat;
        vector<pair<vector<int>::iterator, vector<int>::iterator>> range;

    public:
        groupings_generator(vector<vector<int>> const &orig) : curr(curr_flat) {
            curr_flat.reserve(12);
            for (auto const &r: orig) {
                for (auto x: r) {
                    curr_flat.push_back(x);
                }
            }

            auto it = curr_flat.begin();
            for (size_t i = 0; i < orig.size(); i++) {
                if (orig[i].size() > 2) {
                    range.push_back(make_pair(it, it + orig[i].size()));
                }
                sort(it, it + orig[i].size());
                it += orig[i].size();
            }
        }

        mdview const &get_curr() {
            // cerr << "curr_flat: ";
            // copy(curr_flat.begin(), curr_flat.end(), ostream_iterator<int>(cerr, ", "));
            // cerr << "curr: ";
            // for (int i = 0; i < curr.size(); i++) {
            //     cerr << "(" << curr[i][0] << "," << curr[i][1] << "), ";
            // }
            // cerr << endl;
            return curr;
        }
        bool gen_next() {
            bool flag = false;
            for (int i = range.size()-1; i >= 0; i--) {
                if (next_permutation(range[i].first, range[i].second)
                        && next_permutation(range[i].first, range[i].second)) {
                    flag = true;
                    break;
                }
            }
            curr = mdview(curr_flat);
            return flag;
        }
};

int main() {
    int h, w;
    cin >> h >> w;
    vector<string> chars(h);
    for (int i = 0; i < h; i++) {
        cin >> chars[i];
    }

    vector<map<char,int>> cnth(h);
    vector<map<char,int>> cntw(w);
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            cnth[i][chars[i][j]]++;
            cntw[j][chars[i][j]]++;
        }
    }

    vector<int> hg, wg;
    int hgc, wgc;
    tie(hg, hgc) = organize(chars, cnth, h, true);
    tie(wg, wgc) = organize(chars, cntw, w, false);
    if (hgc == -1 || wgc == -1) { cout << "NO" << endl; return 0; }

    vector<vector<int>> hgv(hgc), wgv(wgc);
    for (int i = 0; i < h; i++) {
        if (hg[i] != -1) hgv[hg[i]].push_back(i);
    }
    for (int i = 0; i < w; i++) {
        if (wg[i] != -1) wgv[wg[i]].push_back(i);
    }

    // ll cnt = 0;
    groupings_generator hgen(hgv);
    groupings_generator wgen(wgv);
    auto const &hgp = hgen.get_curr();
    do {
        auto const &wgv = wgen.get_curr();

        if (calc(chars, hgp, wgv)) {
            cout << "YES" << endl;
            return 0;
        }
        // cerr << cnt++ << endl;
    } while (wgen.gen_next());

    cout << "NO" << endl;

    return 0;
}


Measured memory_bytes: 256