// Original C++ solution (slower):
//include

//------------------------------------------

#include <bits/stdc++.h>

using namespace std;



//typedef

//------------------------------------------

typedef long long LL;

typedef vector<LL> VL;

typedef vector<VL> VVL;

typedef vector<string> VS;

typedef pair<LL, LL> PLL;



//container util

//------------------------------------------

#define ALL(a)  (a).begin(),(a).end()

#define RALL(a) (a).rbegin(), (a).rend()

#define SORT(c) sort((c).begin(),(c).end())

#define RSORT(c) sort((c).rbegin(),(c).rend())



//constant

//--------------------------------------------

const double EPS = 1e-10;

const double PI  = acos(-1.0);

const int MOD = 1000000007;



// grid

//--------------------------------------------

VL dx = {0, 1, 0, -1};

VL dy = {1, 0, -1, 0};

VL dx2 = {-1, 0, 1, -1, 1, -1, 0, 1};

VL dy2 = {-1, -1, -1, 0, 0, 1, 1, 1};



//debug

//--------------------------------------------

#define dump(x)  cerr << #x << " = " << (x) << endl

#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl



//IO accelerate

//--------------------------------------------

struct InitIO {

    InitIO() {

        cin.tie(nullptr);

        ios_base::sync_with_stdio(false);

        cout << fixed << setprecision(30);

    }

} init_io;



//template

//--------------------------------------------

template<typename T>

istream& operator >>(istream& is, vector<T>& vec) {

  for(T& x: vec) is >> x;

  return is;

}

template<typename T>

ostream& operator <<(ostream& os, const vector<T>& vec) {

  for(int i=0; i<vec.size(); i++){

    os << vec[i] << ( i+1 == vec.size() ? "" : "\t" );

  }

  return os;

}

template<typename T>

ostream& operator <<(ostream& s, const vector<vector<T>>& vv) {

	for (int i = 0; i < vv.size(); ++i) {

		s << vv[i] << endl;

	}

	return s;

}

template<typename T>

ostream& operator <<(ostream& s, const vector<pair<T, T>>& vp) {

	for (int i = 0; i < vp.size(); ++i) {

		s << "(" << vp[i].first << "," << vp[i].second << ")" << ( i+1 == vp.size() ? "" : ",\t" );

	}

	return s;

}



// 多重vector

// auto dp=make_v<int>(4,h,w) みたいに使える

template<typename T>

vector<T> make_v(size_t a){return vector<T>(a);}



template<typename T,typename... Ts>

auto make_v(size_t a,Ts... ts){

  return vector<decltype(make_v<T>(ts...))>(a,make_v<T>(ts...));

}



// 多重vectorのためのfill

// fill_v(dp,0) みたいに使える

template<typename T,typename V>

typename enable_if<is_class<T>::value==0>::type

fill_v(T &t,const V &v){t=v;}



template<typename T,typename V>

typename enable_if<is_class<T>::value!=0>::type

fill_v(T &t,const V &v){

  for(auto &e:t) fill_v(e,v);

}



//main code



int main(int argc, char const* argv[])

{

	int n;

	string s;

	cin >> n >> s;

	VVL num(10);

	for (int i = 0; i < n; i++) {

		num[s[i] - '0'].push_back(i);

	}

	set<int> ans;

	for (int i = 0; i < 1000; i++) {

		int n3 = i/100;

		int n2 = (i%100)/10;

		int n1 = i%10;

		VL s3 = num[n3];

		VL s2 = num[n2];

		VL s1 = num[n1];

		if (s3.size() == 0 or s2.size() == 0 or s1.size() == 0) {

			continue;

		}

		int i3 = s3[0];

		int i1 = s1.back();

		for (int j = 0; j < s2.size(); j++) {

			if (s2[j] > i3 and i1 > s2[j]) {

				ans.insert(i);

				goto end_loop;

			}

		}

end_loop:

		int dumy;

	}

	cout << ans.size() << endl;

	return 0;

}


// Optimized solution to the same problem (faster):
//include

//------------------------------------------

#include <bits/stdc++.h>

using namespace std;



//typedef

//------------------------------------------

typedef long long LL;

typedef vector<LL> VL;

typedef vector<VL> VVL;

typedef vector<string> VS;

typedef pair<LL, LL> PLL;



//container util

//------------------------------------------

#define ALL(a)  (a).begin(),(a).end()

#define RALL(a) (a).rbegin(), (a).rend()

#define SORT(c) sort((c).begin(),(c).end())

#define RSORT(c) sort((c).rbegin(),(c).rend())



//constant

//--------------------------------------------

const double EPS = 1e-10;

const double PI  = acos(-1.0);

const int MOD = 1000000007;



// grid

//--------------------------------------------

VL dx = {0, 1, 0, -1};

VL dy = {1, 0, -1, 0};

VL dx2 = {-1, 0, 1, -1, 1, -1, 0, 1};

VL dy2 = {-1, -1, -1, 0, 0, 1, 1, 1};



//debug

//--------------------------------------------

#define dump(x)  cerr << #x << " = " << (x) << endl

#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl



//IO accelerate

//--------------------------------------------

struct InitIO {

    InitIO() {

        cin.tie(nullptr);

        ios_base::sync_with_stdio(false);

        cout << fixed << setprecision(30);

    }

} init_io;



//template

//--------------------------------------------

template<typename T>

istream& operator >>(istream& is, vector<T>& vec) {

  for(T& x: vec) is >> x;

  return is;

}

template<typename T>

ostream& operator <<(ostream& os, const vector<T>& vec) {

  for(int i=0; i<vec.size(); i++){

    os << vec[i] << ( i+1 == vec.size() ? "" : "\t" );

  }

  return os;

}

template<typename T>

ostream& operator <<(ostream& s, const vector<vector<T>>& vv) {

	for (int i = 0; i < vv.size(); ++i) {

		s << vv[i] << endl;

	}

	return s;

}

template<typename T>

ostream& operator <<(ostream& s, const vector<pair<T, T>>& vp) {

	for (int i = 0; i < vp.size(); ++i) {

		s << "(" << vp[i].first << "," << vp[i].second << ")" << ( i+1 == vp.size() ? "" : ",\t" );

	}

	return s;

}



// 多重vector

// auto dp=make_v<int>(4,h,w) みたいに使える

template<typename T>

vector<T> make_v(size_t a){return vector<T>(a);}



template<typename T,typename... Ts>

auto make_v(size_t a,Ts... ts){

  return vector<decltype(make_v<T>(ts...))>(a,make_v<T>(ts...));

}



// 多重vectorのためのfill

// fill_v(dp,0) みたいに使える

template<typename T,typename V>

typename enable_if<is_class<T>::value==0>::type

fill_v(T &t,const V &v){t=v;}



template<typename T,typename V>

typename enable_if<is_class<T>::value!=0>::type

fill_v(T &t,const V &v){

  for(auto &e:t) fill_v(e,v);

}



//main code



int main(int argc, char const* argv[])

{

	int n;

	string s;

	cin >> n >> s;

	VVL num(10);

	for (int i = 0; i < n; i++) {

		num[s[i] - '0'].push_back(i);

	}

	LL ans = 0;

	for (int n3 = 0; n3 < 10; n3++) {

		for (int n2 = 0; n2 < 10; n2++) {

			for (int n1 = 0; n1 < 10; n1++) {

				VL &s3 = num[n3];

				VL &s2 = num[n2];

				VL &s1 = num[n1];

				if (s3.empty() or s2.empty() or s1.empty()) {

					continue;

				}

				int i3 = s3.front();

				int i1 = s1.back();

				if (i1 <= i3) {

					continue;

				}

				auto i2 = upper_bound(ALL(s2), i3);

				if (i2 != s2.end()) {

					if (*i2 < i1) {

						ans++;

					}

				}

			}

		}

	}

	cout << ans << endl;

	return 0;

}


// Fastest known solution for this problem: