#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cassert>
using namespace std;
#define MOD @
#define ADD(X,Y) ((X) = ((X) + (Y)%MOD) % MOD)
typedef long long i64; typedef vector<int> ivec; typedef vector<string> svec;

namespace atcoder {
namespace internal {

template <class E> struct csr {
    std::vector<int> start;
    std::vector<E> elist;
    csr(int n, const std::vector<std::pair<int, E>>& edges)
        : start(n + 1), elist(edges.size()) {
        for (auto e : edges) {
            start[e.first + 1]++;
        }
        for (int i = 1; i <= n; i++) {
            start[i] += start[i - 1];
        }
        auto counter = start;
        for (auto e : edges) {
            elist[counter[e.first]++] = e.second;
        }
    }
};

// Reference:
// R. Tarjan,
// Depth-First Search and Linear Graph Algorithms
struct scc_graph {
  public:
    scc_graph(int n) : _n(n) {}

    int num_vertices() { return _n; }

    void add_edge(int from, int to) { edges.push_back({from, {to}}); }

    // @return pair of (# of scc, scc id)
    std::pair<int, std::vector<int>> scc_ids() {
        auto g = csr<edge>(_n, edges);
        int now_ord = 0, group_num = 0;
        std::vector<int> visited, low(_n), ord(_n, -1), ids(_n);
        visited.reserve(_n);
        auto dfs = [&](auto self, int v) -> void {
            low[v] = ord[v] = now_ord++;
            visited.push_back(v);
            for (int i = g.start[v]; i < g.start[v + 1]; i++) {
                auto to = g.elist[i].to;
                if (ord[to] == -1) {
                    self(self, to);
                    low[v] = std::min(low[v], low[to]);
                } else {
                    low[v] = std::min(low[v], ord[to]);
                }
            }
            if (low[v] == ord[v]) {
                while (true) {
                    int u = visited.back();
                    visited.pop_back();
                    ord[u] = _n;
                    ids[u] = group_num;
                    if (u == v) break;
                }
                group_num++;
            }
        };
        for (int i = 0; i < _n; i++) {
            if (ord[i] == -1) dfs(dfs, i);
        }
        for (auto& x : ids) {
            x = group_num - 1 - x;
        }
        return {group_num, ids};
    }

    std::vector<std::vector<int>> scc() {
        auto ids = scc_ids();
        int group_num = ids.first;
        std::vector<int> counts(group_num);
        for (auto x : ids.second) counts[x]++;
        std::vector<std::vector<int>> groups(ids.first);
        for (int i = 0; i < group_num; i++) {
            groups[i].reserve(counts[i]);
        }
        for (int i = 0; i < _n; i++) {
            groups[ids.second[i]].push_back(i);
        }
        return groups;
    }

  private:
    int _n;
    struct edge {
        int to;
    };
    std::vector<std::pair<int, edge>> edges;
};

}  // namespace internal

// Reference:
// B. Aspvall, M. Plass, and R. Tarjan,
// A Linear-Time Algorithm for Testing the Truth of Certain Quantified Boolean
// Formulas
struct two_sat {
  public:
    two_sat() : _n(0), scc(0) {}
    two_sat(int n) : _n(n), _answer(n), scc(2 * n) {}

    void add_clause(int i, bool f, int j, bool g) {
        assert(0 <= i && i < _n);
        assert(0 <= j && j < _n);
        scc.add_edge(2 * i + (f ? 0 : 1), 2 * j + (g ? 1 : 0));
        scc.add_edge(2 * j + (g ? 0 : 1), 2 * i + (f ? 1 : 0));
    }
    bool satisfiable() {
        auto id = scc.scc_ids().second;
        for (int i = 0; i < _n; i++) {
            if (id[2 * i] == id[2 * i + 1]) return false;
            _answer[i] = id[2 * i] < id[2 * i + 1];
        }
        return true;
    }
    std::vector<bool> answer() { return _answer; }

  private:
    int _n;
    std::vector<bool> _answer;
    internal::scc_graph scc;
};

}  // namespace atcoder


int N, A[100], B[100]; vector<int> poss[33];
int lf[2][100], rg[2][100];

void compute_lfrg(int t, int* seq) {
	for (int i = 0; i < N; ++i) lf[t][i] = -1;
	for (int i = 0; i < 3 * N; ++i) {
		int v = seq[i];
		if (lf[t][v] == -1) lf[t][v] = i;
		rg[t][v] = i;
	}
}

bool overlap(int t, int x, int y) {
	return !(rg[t][y] < lf[t][x] || rg[t][x] < lf[t][y]);
}

int solve(int L, int R) {
	int cnt[33];
	vector<int> pl[33], pr[33]; // from inside to outside
	for (int i = 0; i < N; ++i) cnt[i] = 0;
	for (int i = L - 1; i >= 0; --i) pl[B[i]].push_back(i);
	for (int i = R; i < 3 * N; ++i) pr[B[i]].push_back(i);

	for (int i = 0; i < N; ++i) {
		if (pl[i].size() == 3 || pr[i].size() == 3) return false;
	}

	int rl[100], rr[100]; // reachable left/right
	for (int i = 0; i < 3 * N; ++i) {
		rl[i] = -1;
		rr[i] = 1000;
	}
	for (int i = 0; i < L; ++i) rl[i] = i;
	for (int i = R; i < 3 * N; ++i) rr[i] = i;

	int dmin[100], dmax[100];
	vector<pair<pair<int, int>, pair<int, int>>> conds;
	vector<int> conds_pos;
	for (int i = L; i < R; ++i) {
		int v = B[i];
		int nmov = pl[v].size() + pr[v].size();

		dmin[i] = -1;
		if (nmov == 0) {
			dmin[i] = poss[v][cnt[v]];
		} else if (nmov == 1) {
			dmin[i] = poss[v][cnt[v] * 2];
		} else if (nmov == 2) {
			if (pl[v].size() == 2) {
				dmin[i] = poss[v][2];
			} else if (pr[v].size() == 2) {
				dmin[i] = poss[v][0];
			} else {
				// difficult pattern...
				conds.push_back({{pl[v][0], pr[v][0]}, {poss[v][0], poss[v][2]}});
				conds_pos.push_back(i);
			}
		} else if (nmov == 3) { // never called
			// aux edge x -> y -> z
			int x, y, z;
			if (pl[v].size() == 2) {
				x = pl[v][0];
				y = pr[v][1];
				z = pl[v][1];

				rr[x] = std::min(rr[x], y);
				rl[y] = std::max(rl[y], z);
			} else {
				x = pr[v][0];
				y = pl[v][1];
				z = pr[v][1];

				rl[x] = std::max(rl[x], y);
				rr[y] = std::min(rr[y], z);
			}
		}
		dmax[i] = dmin[i];
		if (dmax[i] == -1) dmax[i] = 100000;
		++cnt[v];
	}
	for (int v = 0; v < N; ++v) {
		int nmov = pl[v].size() + pr[v].size();
		if (nmov == 3) {
			// aux edge x -> y -> z
			int x, y, z;
			if (pl[v].size() == 2) {
				x = pl[v][0];
				y = pr[v][0];
				z = pl[v][1];

				//rr[x] = std::min(rr[x], y);
				rl[y] = std::max(rl[y], z);
			} else {
				x = pr[v][0];
				y = pl[v][0];
				z = pr[v][1];

				//rl[x] = std::max(rl[x], y);
				rr[y] = std::min(rr[y], z);
			}
		}
	}

	for (int i = L + 1; i < R; ++i) {
		if (dmin[i - 1] != -1) dmin[i] = max(dmin[i], dmin[i - 1] + 1);
	}
	for (int i = R - 2; i >= L; --i) {
		if (dmax[i + 1] != -1) {
			if (dmax[i] == -1) dmax[i] = dmax[i + 1] - 1;
			else dmax[i] = min(dmax[i], dmax[i + 1] - 1);
		}
	}
	for (int i = L; i < R; ++i) {
		if (dmin[i] > dmax[i]) return false;
	}

	for (int t = 0; t < 2; ++t) {
		for (int i = 0; i < L; ++i) {
			if (i > 0) {
				rl[i] = std::max(rl[i], rl[i - 1]);
				rr[i] = std::min(rr[i], rr[i - 1]);
			}
			if (rr[i] < 100) rl[i] = std::max(rl[i], rl[rr[i]]);
		}
		for (int i = 3 * N - 1; i >= R; --i) {
			if (i != 3 * N - 1) {
				rl[i] = std::max(rl[i], rl[i + 1]);
				rr[i] = std::min(rr[i], rr[i + 1]);
			}
			if (rl[i] >= 0) rr[i] = std::min(rr[i], rr[rl[i]]);
		}
	}
	for (int i = 0; i < L; ++i) if (rl[i] != i) return false;
	for (int i = R; i < 3 * N; ++i) if (rr[i] != i) return false;

	// preserve left (in sequence A): true, right: false
	atcoder::two_sat ts(conds.size());
	auto reachable = [&](int x, int y) {
		if (x < L && y < L) return x >= y;
		if (x >= R && y >= R) return x <= y;
		if (x < L && y >= R) return rr[x] <= y;
		if (x >= R && y < L) return rl[x] >= y;
	};

	for (int i = 0; i < conds.size(); ++i) {
		int bl0 = conds[i].first.first;
		int br0 = conds[i].first.second;
		int al0 = conds[i].second.first;
		int ar0 = conds[i].second.second;

		int ip = conds_pos[i];
		if (ar0 < dmin[ip]) return false;
		if (dmax[ip] < al0) return false;

		if (al0 < dmin[ip] || reachable(bl0, br0)) ts.add_clause(i, true, i, true);
		if (dmax[ip] < ar0 || reachable(br0, bl0)) ts.add_clause(i, false, i, false);

		for (int j = i + 1; j < conds.size(); ++j) {
			int bl1 = conds[j].first.first;
			int br1 = conds[j].first.second;
			int al1 = conds[j].second.first;
			int ar1 = conds[j].second.second;

			if (al0 > al1) ts.add_clause(i, !false, j, !false);
			if (al0 > ar1) ts.add_clause(i, !false, j, !true);
			if (ar0 > al1) ts.add_clause(i, !true, j, !false);
			if (ar0 > ar1) ts.add_clause(i, !true, j, !true);

			// i: left, j: left
			if (reachable(bl1, br0) && reachable(bl0, br1)) ts.add_clause(i, true, j, true);

			// i: left, j: right
			if (reachable(br1, br0) && reachable(bl0, bl1)) ts.add_clause(i, true, j, false);

			// i: right, j: left
			if (reachable(bl1, bl0) && reachable(br0, br1)) ts.add_clause(i, false, j, true);

			// i: right, j: right
			if (reachable(br1, bl0) && reachable(br0, bl1)) ts.add_clause(i, false, j, false);
		}
	}

	return ts.satisfiable();
}

int main()
{
	scanf("%d", &N);
	for (int i = 0; i < 3 * N; ++i) {
		scanf("%d", A + i); --A[i];
	}
	for (int i = 0; i < 3 * N; ++i) poss[A[i]].push_back(i);
	for (int i = 0; i < 3 * N; ++i) {
		scanf("%d", B + i); --B[i];
	}
	int ans = 101010;
	for (int L = 0; L <= 3 * N; ++L) {
		for (int R = L; R <= 3 * N; ++R) {
			if (solve(L, R)) {
				ans = min(ans, 3 * N - (R - L));
			}
		}
	}
	if (ans > 10000) ans = -1;
	printf("%d\n", ans);
	return 0;
}


Measured memory_bytes: 3324