table of Contents
13. Roman Numerals to Integers
The dictionary stores data in the form of Key/Value (key-value pairs); the biggest advantage of this class is that its time complexity for finding elements is close to O(1), and it is often used as a local cache of some data in actual projects. Overall efficiency.
1. Algorithm application
13. Roman Numerals to Integers
- Title description
Roman numerals contain the following seven characters: I, V, X, L, C, D and M.
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
For example, the Roman numeral 2 is written as II, which means two parallel ones. 12 is written as XII, which means X + II. 27 is written as XXVII, which is XX + V + II.
Normally, the small numbers in Roman numerals are to the right of the large numbers. But there are special cases, for example, 4 is not written as IIII, but as IV. The number 1 is to the left of the number 5, and the number represented is equal to the number 4 obtained by subtracting the number 1 from the large number 5. Similarly, the number 9 is represented as IX. This special rule only applies to the following six situations:
- I can be placed to the left of V (5) and X (10) to represent 4 and 9.
- X can be placed to the left of L (50) and C (100) to represent 40 and 90.
- C can be placed to the left of D (500) and M (1000) to represent 400 and 900.
Given a Roman numeral, convert it to an integer. Ensure that the input is in the range of 1 to 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.
- Problem-solving ideas
The way to use the dictionary. Treat the dictionary as a storage container, key
store all combinations of Roman characters, and value
store the values represented by the combinations. Each time one character is taken, it is judged whether there are any characters after this character. If there are, it is judged whether these two characters are in the dictionary, and the value is taken if they exist. Otherwise, just get the value according to one character.
- C++ algorithm implementation
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 Caching Mechanism
- Title description
Use the data structure you know to design and implement an LRU (least recently used) caching mechanism. It should support the following operations: Get data get and write data put.
Get data get(key)-If the key exists in the cache, get the value of the key (always a positive number), otherwise return -1.
Write data put(key, value)-If the key already exists, change its data value; if the key does not exist, insert the set of "key/value". When the cache capacity reaches the upper limit, it should delete the oldest unused data value before writing new data to make room for the new data value.
Advanced:
Can you complete these two operations in O(1) time complexity?
示例:
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
- Problem-solving ideas
Use dictionary + list method
The computer's cache capacity is limited. If the cache is full, some content will be deleted to make room for new content. But the question is, what should be deleted? We definitely hope to delete the useless caches, and keep the useful data in the caches for future use. So, what kind of data do we judge as "useful" data?
The LRU cache elimination algorithm is a common strategy. The full name of LRU is Least Recently Used, which means that we believe that data that has been used recently should be "useful", and data that has not been used for a long time should be useless. When the memory is full, delete those that have not been used for a long time. data.
Because obviously the cache must be in order to distinguish between the most recently used and long-unused data; and we need to find out whether the key already exists in the cache; if the capacity is full, delete the last data; insert the data for each access To the head of the team.
So, what data structure meets the above conditions at the same time? Hash table lookup is fast, but the data has no fixed order; the linked list has order, insertion and deletion are fast, but lookup is slow. So combine it to form a new data structure: hash linked list.
The core data structure of the LRU cache algorithm is a combination of hash linked list, doubly linked list and hash table. The idea is very simple, that is, with the help of the hash table to give the linked list the feature of fast search: you can quickly find whether a key exists in the cache (linked list), and at the same time you can quickly delete and add nodes. Recalling the previous example, does this data structure perfectly solve the needs of LRU caching?
Think of a dictionary as a storage container. Since the dictionary is unordered, that is, the order of dict
internal storage key
is irrelevant to the order in which it is placed, so one list
is needed to assist in sorting.
- C++ algorithm implementation
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();
}
}
};
Reference link:
The Application of Dictionary Technology in Solving Algorithmic Problems