#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>;
const int INF = 1e9;
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int n, m;
    if (!(cin >> n >> m)) return 0;
    vector<vector<pair<int,int>>> out(n+1); // out[u] = list of (v, color)
    vector<tuple<int,int,int>> edges;
    edges.reserve(m);
    for (int i = 0; i < m; ++i) {
        int u, v, c;
        cin >> u >> v >> c;
        edges.emplace_back(u,v,c);
        out[u].push_back({v,c});
    }
 
    if (n == 1) { // already at destination
        cout << 0 << '\n';
        return 0;
    }
 
    // For each node v, collect set of incoming colors (colors of edges that end at v)
    vector<unordered_map<int,int>> color_id(n+1);
    color_id.assign(n+1, unordered_map<int,int>());
 
    for (auto &t : edges) {
        int u,v,c;
        tie(u,v,c) = t;
        if (color_id[v].find(c) == color_id[v].end()) {
            int id = (int)color_id[v].size();
            color_id[v][c] = id;
        }
        // Note: we don't need colors for u unless there is incoming edge to u
    }
 
    // assign global ids to each (v, color)
    vector<int> base_index(n+1, 0); // base_index[v] = starting id for node v in dist array
    int total_states = 0;
    for (int v = 1; v <= n; ++v) {
        base_index[v] = total_states;
        total_states += (int)color_id[v].size();
    }
    if (total_states == 0) {
        // no edge enters any node => impossible unless n==1 (handled)
        cout << -1 << '\n';
        return 0;
    }
 
    auto get_state = [&](int v, int color) -> int {
        auto it = color_id[v].find(color);
        if (it == color_id[v].end()) return -1;
        return base_index[v] + it->second;
    };
 
    vector<int> dist(total_states, INF);
    deque<int> dq;
 
    // Initialize: from node 1 (no previous color), taking any outgoing edge (1->v,color)
    // leads to state (v,color) with cost 0 (first edge never counts as a color-change).
    for (auto &p : out[1]) {
        int v = p.first;
        int c = p.second;
        int sid = get_state(v, c);
        if (sid == -1) continue; // shouldn't happen but safe
        if (dist[sid] > 0) {
            dist[sid] = 0;
            dq.push_front(sid);
        }
    }
 
    // 0-1 BFS over states
    while (!dq.empty()) {
        int cur = dq.front(); dq.pop_front();
        int curd = dist[cur];
        // decode cur -> (u,color_prev)
        // We need to know which node u this state belongs to and the color value.
        // To decode, find node v such that base_index[v] <= cur < base_index[v] + color_id[v].size()
        // We'll binary search over base_index since base_index is monotonic.
        // Simpler: build reverse mapping arrays of state -> (node, color_value).
        break;
    }
 
    // Because we need decode, rebuild reverse arrays:
    vector<int> state_node(total_states), state_color(total_states);
    for (int v = 1; v <= n; ++v) {
        for (auto &kv : color_id[v]) {
            int color = kv.first;
            int idx = kv.second;
            int sid = base_index[v] + idx;
            state_node[sid] = v;
            state_color[sid] = color;
        }
    }
 
    // Reinitialize dist and deque, then run proper BFS
    fill(dist.begin(), dist.end(), INF);
    dq.clear();
    for (auto &p : out[1]) {
        int v = p.first, c = p.second;
        int sid = get_state(v, c);
        if (sid == -1) continue;
        if (dist[sid] > 0) {
            dist[sid] = 0;
            dq.push_front(sid);
        }
    }
 
    while (!dq.empty()) {
        int cur = dq.front(); dq.pop_front();
        int curd = dist[cur];
        int u = state_node[cur];
        int color_prev = state_color[cur];
 
        // from (u, color_prev) try all outgoing edges (u -> v, c)
        for (auto &e : out[u]) {
            int v = e.first;
            int c = e.second;
            int nxt = get_state(v, c);
            if (nxt == -1) continue; // state not present (shouldn't happen)
            int add = (c == color_prev) ? 0 : 1;
            if (dist[nxt] > curd + add) {
                dist[nxt] = curd + add;
                if (add == 0) dq.push_front(nxt);
                else dq.push_back(nxt);
            }
        }
    }
 
    // answer = min dist over all states that correspond to node n
    int best = INF;
    if (!color_id[n].empty()) {
        for (auto &kv : color_id[n]) {
            int sid = base_index[n] + kv.second;
            best = min(best, dist[sid]);
        }
    }
    // Also consider direct edge 1->n: we initialized those states with 0 already; if there is no incoming color to n (no edges into n),
    // then impossible. (Handled above)
    if (best == INF) cout << -1 << '\n';
    else cout << best << '\n';
 
    return 0;
}