[アルゴリズムシリーズ(6)]:辞書

目次

1.アルゴリズムアプリケーション

13.ローマ数字を整数に変換する

 146.LRUキャッシングメカニズム


ディクショナリはデータをキー/値(キーと値のペア)の形式で格納します。このクラスの最大の利点は、要素を見つけるための時間計算量がO(1)に近く、のローカルキャッシュとしてよく使用されることです。実際のプロジェクトのいくつかのデータ。全体的な効率。

1.アルゴリズムアプリケーション

13.ローマ数字を整数に変換する

  • タイトル説明

ローマ数字には、I、V、X、L、C、D、Mの7文字が含まれています。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

たとえば、ローマ数字2はIIと表記され、2つの平行なものを意味します。12はXIIと表記され、X + IIを意味します。27はXXVII、つまりXX + V + IIと表記されます。

通常、ローマ数字の小さい数字は大きい数字の右側にあります。ただし、特殊なケースがあります。たとえば、4はIIIIとしてではなく、IVとして記述されます。数字の1は数字の5の左側にあり、表されている数字は、大きな数字の5から数字の1を引いた数字の4と同じです。同様に、番号9はIXとして表されます。この特別なルールは、次の6つの状況にのみ適用されます。

  • V(5)とX(10)の左側に配置して、4と9を表すことができます。
  • XはL(50)とC(100)の左側に配置して、40と90を表すことができます。 
  • CはD(500)とM(1000)の左側に配置して、400と900を表すことができます。

ローマ数字が与えられたら、それを整数に変換します。入力が1〜3999の範囲にあることを確認してください。

示例 1:
输入:"III"
输出: 3

示例 2:
输入: "IV"
输出: 4

示例 3:
输入: "IX"
输出: 9

示例 4:
输入: "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.

示例 5:
输入: "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
  • 問題解決のアイデア

辞書の使い方。辞書をストレージコンテナとして扱い、key ローマ字のすべての組み合わせをvalue 保存し、組み合わせによって表される値保存します。1文字を取るたびに、この文字の後に文字があるかどうかが判断されます。存在する場合は、この2文字が辞書にあるかどうかを判断し、存在する場合は値を取得します。それ以外の場合は、1文字に従って値を取得します。

  • C ++アルゴリズムの実装 
 int romanToInt(string s) {
	 map<string, int> dict = { {"I", 1}, {"II" , 2}, {"IV" , 4}, {"IX" , 9}, {"X" , 10}, {"XL" , 40}, {"XC" , 90},
	 {"C" , 100}, {"CD", 400}, {"CM" , 900}, {"V" , 5},{"L" , 50}, {"D" , 500}, {"M" , 1000} };

	 int res = 0;
	 int i = 0;
	 while (i < s.size()) {
		 string tmp(1,s[i]);
		 if (i + 1 < s.size()) {
			 if (dict.find(tmp+s[i+1]) != dict.end()) {
				 res += dict[tmp + s[i + 1]];
				 i += 2;
			 }
			 else {
				 res += dict[tmp];
				 i += 1;
			 }
			 
		 }
		 else {
			 res += dict[tmp];
			 i += 1;
			
		 }
		 
	 }

	 return res;
 }

 146.LRUキャッシングメカニズム

  • タイトル説明

知っているデータ構造を使用して、LRU(最近使用されていない)キャッシュメカニズムを設計および実装します。次の操作をサポートする必要があります。データの取得とデータの書き込み。

データの取得get(key)-キーがキャッシュに存在する場合は、キーの値(常に正の数)を取得します。それ以外の場合は-1を返します。
データの書き込みput(key、value)-キーがすでに存在する場合は、そのデータ値を変更します。キーが存在しない場合は、「キー/値」のセットを挿入します。キャッシュ容量が上限に達すると、新しいデータを書き込む前に最も古い未使用のデータ値を削除して、新しいデータ値のためのスペースを確保する必要があります。

上級:

これらの2つの操作をO(1)時間計算量で完了できますか?

示例:

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作会使得关键字 2 作废
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 该操作会使得关键字 1 作废
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4
  • 問題解決のアイデア

辞書+リスト方式を使用する

コンピュータのキャッシュ容量には制限があります。キャッシュがいっぱいになると、一部のコンテンツが削除され、新しいコンテンツ用のスペースが確保されます。しかし、問題は、何を削除する必要があるかということです。無駄なキャッシュを削除し、将来の使用に備えて有用なデータをキャッシュに保持したいと考えています。では、どのようなデータを「有用な」データと判断するのでしょうか。

LRUキャッシュ除去アルゴリズムは一般的な戦略です。LRUのフルネームは「最近使用されていない」です。つまり、最近使用されたデータは「有用」であり、長期間使用されていないデータは役に立たないと考えられます。メモリがいっぱいになったら、削除します。長期間使用されていないもの。データ。

明らかに、キャッシュは最近使用されたデータと長期間使用されていないデータを区別するために必要であり、キーがキャッシュにすでに存在するかどうかを確認する必要があるためです。容量がいっぱいの場合は、最後のデータを削除し、データを挿入します。アクセスごとにチームの責任者に。

では、どのデータ構造が同時に上記の条件を満たすのでしょうか?ハッシュテーブルのルックアップは高速ですが、データの順序は固定されていません。リンクリストには順序があり、挿入と削除は高速ですが、ルックアップは低速です。したがって、それを組み合わせて新しいデータ構造を形成します:ハッシュリンクリスト。

LRUキャッシュアルゴリズムのコアデータ構造は、ハッシュリンクリスト、二重リンクリスト、およびハッシュテーブルの組み合わせです。アイデアは非常に単純です。つまり、ハッシュテーブルを使用してリンクリストに高速検索の機能を提供します。つまり、キーがキャッシュ(リンクリスト)に存在するかどうかをすばやく見つけることができ、同時に次のことができます。ノードをすばやく削除および追加します。前の例を思い出して、このデータ構造はLRUキャッシングのニーズを完全に解決しますか?

辞書はストレージコンテナと考えてください。辞書は順序付けられていないため、つまり、 dict 内部ストレージ key の順序は配置されている順序とは無関係であるためlist 、並べ替えを支援する必要があります 

  • C ++アルゴリズムの実装
class LRUCache {
 public:
	 unordered_map<int, list<pair<int,int>>::iterator> hash_map;
	 list<pair<int,int>> head_cache;
	 int cap;

 public:
	 LRUCache(int capacity) {
		 cap = capacity;
	 }

	 int get(int key) {
		 if (hash_map.find(key) == hash_map.end()) {
			 return -1;
		 }

		 int val = hash_map[key]->second;
		 put(key, val);//利用put将数据提前

		 return val;
	 }

	 void put(int key, int value) {
		 pair<int, int> p(key, value);

		 if (hash_map.find(key) != hash_map.end()) {
			 head_cache.erase(hash_map[key]);//删除旧节点
			 head_cache.emplace_front(p);//插入到头部
			 hash_map[key] = head_cache.begin();//更新hash map
		 }
		 else {
			 if (cap == head_cache.size()) {
				 pair<int, int> last = head_cache.back();
				 head_cache.pop_back();//删除list最后一个数据
				 hash_map.erase(last.first);//删除map中的数据
			 }

			 //向头部添加数据
			 head_cache.emplace_front(p);
			 hash_map[key] = head_cache.begin();
		 }
	 }
 };

参照リンク:

アルゴリズム問題の解決における辞書技術の応用

詳細なLRUアルゴリズム

おすすめ

転載: blog.csdn.net/wxplol/article/details/108481901