3.17
集合、分治,树
LFU 缓存(hard)
thinking
缓存清除机制:LRU与LFU。LRU可以简单地通过哈希表+双向链表进行实现,LFU则要复杂的多,为双哈希+N个双向链表进行实现
解释好麻烦,不解释了,直接上代码。
solution
//codes from leetcode
struct Node {
int cnt, time, key, value;
Node(int _cnt, int _time, int _key, int _value):cnt(_cnt), time(_time), key(_key), value(_value){}
bool operator < (const Node& rhs) const {
return cnt == rhs.cnt ? time < rhs.time : cnt < rhs.cnt;
}
};
class LFUCache {
// 缓存容量,时间戳
int capacity, time;
unordered_map<int, Node> key_table;
set<Node> S;
public:
LFUCache(int _capacity) {
capacity = _capacity;
time = 0;
key_table.clear();
S.clear();
}
int get(int key) {
if (capacity == 0) return -1;
auto it = key_table.find(key);
// 如果哈希表中没有键 key,返回 -1
if (it == key_table.end()) return -1;
// 从哈希表中得到旧的缓存
Node cache = it -> second;
// 从平衡二叉树中删除旧的缓存
S.erase(cache);
// 将旧缓存更新
cache.cnt += 1;
cache.time = ++time;
// 将新缓存重新放入哈希表和平衡二叉树中
S.insert(cache);
it -> second = cache;
return cache.value;
}
void put(int key, int value) {
if (capacity == 0) return;
auto it = key_table.find(key);
if (it == key_table.end()) {
// 如果到达缓存容量上限
if (key_table.size() == capacity) {
// 从哈希表和平衡二叉树中删除最近最少使用的缓存
key_table.erase(S.begin() -> key);
S.erase(S.begin());
}
// 创建新的缓存
Node cache = Node(1, ++time, key, value);
// 将新缓存放入哈希表和平衡二叉树中
key_table.insert(make_pair(key, cache));
S.insert(cache);
}
else {
// 这里和 get() 函数类似
Node cache = it -> second;
S.erase(cache);
cache.cnt += 1;
cache.time = ++time;
cache.value = value;
S.insert(cache);
it -> second = cache;
}
}
};
词典中最长的单词
thinking
简单模拟即可,不过题目意思说的有点迷糊
solution
class Solution {
public:
string longestWord(vector<string>& w) {
sort(w.begin(),w.end());
int n=w.size();
unordered_set<string> hash;
string ans="z";
for(int i=0;i<n;++i) {
if(w[i].size()==1) {
hash.insert(w[i]);
if(ans.size()==1&&ans>w[i])
ans=w[i];
}
else {
int len=w[i].size();
if(hash.count(w[i].substr(0,len-1))) {
hash.insert(w[i]);
if(len>ans.size()) ans=w[i];
else if(len==ans.size()&&ans>w[i]) ans=w[i];
}
}
}
return hash.empty()?"":ans;
}
};
颠倒二进制位
thinking
简单模拟,倒叙遍历即可
solution
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t ans=0;
for(int i=0;i<32;++i) {
ans|=(n&1)<<(31-i);
n=n>>1;
}
return ans;
}
};
有序链表转换二叉搜索树
thinking
可以参考一下下一题再做此题
solution
class Solution {
public:
TreeNode* BSTbuild(int left,int right,vector<int>&nums) {
int mid=left+(right-left)/2;
TreeNode* node=new TreeNode(nums[mid]);
if(left<mid) node->left=BSTbuild(left,mid-1,nums);
if(mid<right) node->right=BSTbuild(mid+1,right,nums);
return node;
}
TreeNode* sortedListToBST(ListNode* head) {
vector<int> cnt;
while(head) {
cnt.push_back(head->val);
head=head->next;
}
if(cnt.empty()) return nullptr;
return BSTbuild(0,cnt.size()-1,cnt);
}
};
将二叉搜索树变平衡
thinking
手撸AVL?不不不,我们将节点从树上取下,再重新构造二叉平衡树。
由贪心可以知道,我们每次对一半的数组进行构造左右子树,这样的树一定是最平衡的。证明略,参考。
因此,我们每次将数组进行二分,递归地建立二叉平衡树。
solution
class Solution {
public:
vector<int>cnt;
void getnum(TreeNode* root) {
if(root->left) getnum(root->left);
cnt.push_back(root->val);
if(root->right) getnum(root->right);
}
TreeNode* BSTbuild(int left,int right) {
int mid=left+(right-left)/2;
TreeNode* node=new TreeNode(cnt[mid]);
if(left<mid) node->left=BSTbuild(left,mid-1);
if(mid<right) node->right=BSTbuild(mid+1,right);
return node;
}
TreeNode* balanceBST(TreeNode* root) {
getnum(root);
return BSTbuild(0,cnt.size()-1);
}
};
将有序数组转换为二叉搜索树
thinking
与上一题同理,不再多说
solution
class Solution {
public:
TreeNode* BSTbuild(int left,int right,vector<int>&nums) {
int mid=left+(right-left)/2;
TreeNode* node=new TreeNode(nums[mid]);
if(left<mid) node->left=BSTbuild(left,mid-1,nums);
if(mid<right) node->right=BSTbuild(mid+1,right,nums);
return node;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return BSTbuild(0,nums.size()-1,nums);
}
};

浙公网安备 33010602011771号