Leetcode 146. LRU Cache
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据
get
和 写入数据put
。获取数据
get(key)
- 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据put(key, value)
- 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.put(4, 4); // evicts key 1 cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4
解题的想法是,倘若要在O(1)拿到key对应的value,那么最好使用字典来存储,但是字典在删除的时候没法记录到底哪个是最后一位的key-value键值对,因此可以增加一个链表或者数组存一下当前位置,之前用双向链表写过,因此此处加了一个字典和数组又实现了一次。多加了一个拥有 insert()头部插入 和 pop()尾部弹出的数组记录位置,难点在于每次 get / put 碰到已经有的key值该如何处理,新增了一个 字典 frequency 来记录该 key 出现的频率, 如果在 stack满的时候检查尾部的key值出现过2次以及2次以上,就连续pop()出来,同时减少frequency的数值。
代码如下:
class LRUCache(object):
def __init__(self, capacity):
"""
:type capacity: int
"""
self.dic = {} #dic include key-value
self.stack = [] # save the order of key
self.maxLength = capacity
self.curLength = 0
self.frequency ={}
def get(self, key):
"""
:type key: int
:rtype: int
"""
if(len(self.dic)==0 or not(self.dic.has_key(key))):
return -1
else:
curIndex = self.stack.index(key)
self.stack.insert(0, key)
self.frequency[key] += 1
return self.dic[key]
def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: None
"""
if(self.dic.has_key(key)):
self.dic[key] = value
curIndex = self.stack.index(key)
self.stack.insert(0,key)
self.frequency[key] += 1
elif(self.curLength < self.maxLength):
self.curLength = self.curLength + 1
self.stack.insert(0, key)
if(self.frequency.has_key(key)):
self.frequency[key] += 1
else:
self.frequency[key] = 1
self.dic[key] = value
elif(self.curLength == self.maxLength):
outKey = self.stack.pop()
while(self.frequency[outKey] > 1):
self.frequency[outKey] -= 1
outKey = self.stack.pop()
self.frequency[outKey] -=1
del self.dic[outKey]
self.stack.insert(0, key)
if(self.frequency.has_key(key)):
self.frequency[key] += 1
else:
self.frequency[key] = 1
self.dic[key] = value
其中遇到的问题是,对python的内置方法不熟,导致一直觉得pop是在头部出来而 append是在尾部进去,因此浪费了很多时间。
对操作系统的LRU没理解好,一直以为就是先进先出就好..真是太天真了。
想想这个方法只适用于 数据量较小 或者 有大量重复数据 (cache空间比输入数值多) 的情况,因此在实用上不尽人意吧。
时间 beat 16%+
空间 beat 90%+
虽然这样看感觉双向链表会慢一些,但是其实没慢到哪里去,Leetcode测试平台给的空间损耗差不多,但是时间差了一倍
双向链表 / 字典继承多态方法:
https://leetcode-cn.com/problems/lru-cache/solution/lru-huan-cun-ji-zhi-by-leetcode/
Leetcode 292. Nim Game
You are playing the following Nim Game with your friend: There is a heap of stones on the table, each time one of you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner. You will take the first turn to remove the stones.
Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can win the game given the number of stones in the heap.
Example:
Input:
4
Output: false Explanation: If there are 4 stones in the heap, then you will never win the game; No matter 1, 2, or 3 stones you remove, the last stone will always be removed by your friend.
一道考思维的简单题,先手拿物,只要是现存是4的倍数必输。
代码如下:
class Solution(object):
def canWinNim(self, n):
"""
:type n: int
:rtype: bool
"""
if (n%4) == 0:
return False
else:
return True