(十)数据结构【C++实现】

哈希表

两数之和

Leetcode:https://leetcode-cn.com/problems/two-sum/

1.问题描述

给定一个整数数组,已知有且只有两个数的和等于给定值,求这两个数的位置。

2.输入输出

  • Input:nums = [2, 7, 11, 15],target = 9
  • Output:[0, 1]

3.算法分析

利用哈希表存储遍历过的值以及它们的位置,每次遍历到位置i的时候,查找哈希表里是否存在target-nums[i],若存在,说明这两个值得和为target。

4.编程实现

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:    
    vector<int> twoSum(vector<int>& nums, int target) {        
        unordered_map<int, int> hash;        
        vector<int> ans;                
        for (int i = 0; i < nums.size(); i++) {            
            int num = nums[i];            
            auto pos = hash.find(target - num);                        
            if (pos == hash.end()) {                
                hash[num] = i;            
            } else {                
                ans.push_back(pos->second);                
                ans.push_back(i);                
                break;            
            }        
        }                
        return ans;    
    }
};
int main() {    
    Solution sol;    
    vector<int> nums;    
    int value, target;     
    getchar();
    while (cin >> value) {        
        nums.push_back(value);        
        if (cin.get() == ']') break;    
    }        
    cin >> target;        
    vector<int> ans = sol.twoSum(nums, target);    
    cout << ans[0] << " " << ans[1] << endl;    
    return 0;
}

并查集和LRU等复合数据结构

LRU缓存机制

leetcode 146:https://leetcode-cn.com/problems/lru-cache/
NC93:https://www.nowcoder.com/practice/e3769a5f49894d49b871c09cadd13a61?tpId=188

1.问题描述

设计一个固定大小的,最少最近使用缓存(Least recently used cache,LRU)。每次将信息插入未满的缓存的时候,以及更新或查找一个缓存内存在的信息的时候,将该信息标为最近使用。在缓存未满的情况下将一个新信息插入的时候,需要移除最旧的信息,插入新的信息,并将该信息标为最近使用。

2.输入输出

LRUCache lRUCache = new LRUCache(2);  // 容量为2
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

3.算法分析

【这类题通常采用unordered_map或map辅助记录,从而加速寻址;再配上vector或者list进行数据储存,从而加速连续选址或删除值】

  • 采用链表list<pair<int, int>>来储存信息的key和value,链表的链接顺序即为最近使用的新旧顺序,最新的信息在链表头节点。
  • 同时使用一个嵌套了链表的迭代器的unordered_map<int, list<pair<int, int>>::iterator>进行快速搜索,存迭代器的原因是方便调用链表的splice函数来直接更新查找成功(cash hit)的信息,即把迭代器对应的节点移动为链表的头节点。

4.编程实现

#include <iostream>
#include <vector>
#include <numeric>
#include <list>
#include <unordered_map>
using namespace std;

class LRUCache {  
    // 快速搜索,存迭代器的原因是方便调用链表的splice函数来直接更新查找成功(cash hit)的信息,即把迭代器对应的节点移动为链表的头节点。
    unordered_map<int, list<pair<int, int>>::iterator> hash;  
    list<pair<int, int>> cache;  // 储存信息的key和value,链表的链接顺序即为最近使用的新旧顺序,最新的信息在链表头节点
    int size;
public:
    LRUCache(int capacity) :size(capacity){}  // 以正整数作为容量capacity初始化LRU缓存
    
    int get(int key) {  // 如果关键字key存在于缓存中,则返回关键字的值,否则返回-1
        auto it = hash.find(key);
        if (it == hash.end()) return -1;
        cache.splice(cache.begin(), cache, it->second);
        return it->second->second;
    }
    
    void put(int key, int value) {  // 如果关键字已经存在,则变更其数据值;关键字不存在,则插入该组[关键字-值]
        // 当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据留出空间。
        auto it = hash.find(key);
        if (it != hash.end()) {
            it->second->second = value;
            return cache.splice(cache.begin(), cache, it->second);  // 将它移到表头
        }
        cache.insert(cache.begin(), make_pair(key, value));  // 插入缓存头中
        hash[key] = cache.begin();
        if (cache.size() > size) {
            hash.erase(cache.back().first);
            cache.pop_back();
        }
    }
};

int main() {
    LRUCache *lRUCache = new LRUCache(2);  // 容量为2
    lRUCache->put(1, 1); // 缓存是 {1=1}
    lRUCache->put(2, 2); // 缓存是 {1=1, 2=2}
    cout << lRUCache->get(1) << endl;    // 返回 1
    lRUCache->put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
    cout << lRUCache->get(2)  << endl;    // 返回 -1 (未找到)
    lRUCache->put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
    cout << lRUCache->get(1) << endl;    // 返回 -1 (未找到)
    cout << lRUCache->get(3) << endl;    // 返回 3
    cout << lRUCache->get(4) << endl;    // 返回 4
    
    return 0;
}

有效括号

Leetcode:https://leetcode-cn.com/problems/valid-parentheses/

1.问题描述

给定一个只由左右原括号、花括号和方括号组成的字符串,求这个字符串是否合法。合法的定义是每一类型的左括号都有一个右括号一一对应,且括号内的字符串也满足此要求。

2.输入输出

  • Input:“{[]}()”
  • Output:true

3.算法分析

括号匹配——典型栈问题,从左到右遍历,每当遇到左括号便放入栈内,遇到右括号则判断其和栈顶的括号是否是统一类型,是则从栈内取出左括号,否则说明字符串不合法。

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

4.编程实现

#include <iostream>
#include <stack>
using namespace std;
class Solution {
public:    
    bool isValid(string s) {        
        stack<char> parsed;                
        for (int i = 0; i < s.size(); i++) {            
            if (s[i] == '{' || s[i] == '(' || s[i] == '[') {                
                parsed.push(s[i]);            
            } else {                
                if (parsed.empty()) return false;                
                char c = parsed.top();                
                if ((s[i] == '}' && c == '{') || (s[i] == ')' && c == '(') || (s[i] == ']' && c == '[')) {                        
                    parsed.pop();                    
                } else {                        
                    return false;                    
                }            
            }        
        }        
        return parsed.empty();    
    }
};
int main() {    
    Solution sol;    
    string s;        
    cin >> s;    
    cout << sol.isValid(s) << endl;        
    return 0;
}
posted @ 2021-12-23 10:16  Caoer199  阅读(101)  评论(0编辑  收藏  举报