• (十)数据结构【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;
    }
    
    本文为博主原创文章,未经博主允许禁止转载,需转载请注明出处,欢迎指正!
  • 相关阅读:
    JavaScript 基础(三)
    2015-10-15 第十四节课 补充CSS一些特殊选择器
    2015-09-29 第八节课 JavaScript 基础(二)(js语句:条件、循环)
    2015-09-28 第七节课JavaScript 基础(一) (js简介、声明变量、数据类型)
    2015 09-23 第五节课程(css:仿站及常见代码用法)
    【小练习2】如何制作“表格”
    51nod-1627 瞬间移动(组合数+逆元)
    POJ-3450 Corporate Identity (KMP+后缀数组)
    POJ-2406 Power Strings(KMP)
    CSU-1632 Repeated Substrings (后缀数组)
  • 原文地址:https://www.cnblogs.com/caoer/p/15722190.html
Copyright © 2020-2023  润新知