0801学习
- 单词替换-字节
在英语中,我们有一个叫做 词根(root) 的概念,可以词根后面添加其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。
现在,给定一个由许多词根组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。
你需要输出替换之后的句子。
示例 1:
输入:dictionary = [“cat”,”bat”,”rat”], sentence = “the cattle was rattled by the battery”
输出:”the cat was rat by the bat”
- 单词替换-字节
public class PreWords
{
public char Char;
public bool IsWord;
public Dictionary<char, PreWords> Next = new Dictionary<char, PreWords>();
public PreWords(char c, bool isWord)
{
Char = c;
IsWord = isWord;
}
}
private Dictionary<char, PreWords> __dictionary = new Dictionary<char, PreWords>();
public string ReplaceWords(IList<string> dictionary, string sentence)
{
foreach (var str in dictionary)
{
var first = str[0];
if (!__dictionary.TryGetValue(first, out var p))
{
p = new PreWords(first, false);
__dictionary[first] = p;
}
for (int j = 0; j < str.Length;)
{
if (j == str.Length - 1)
{
p.IsWord = true;
break;
}
if (!p.Next.TryGetValue(str[++j], out var next))
{
next = new PreWords(str[j], false);
p.Next[str[j]] = next;
}
p = next;
}
}
var successores = sentence.Split();
var sb = new StringBuilder();
foreach (var successor in successores)
{
__ReplaceStr(successor, sb);
}
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
private void __ReplaceStr(string successor, StringBuilder sb)
{
if (successor.Length > 0)
{
var first = successor[0];
if (__dictionary.TryGetValue(first, out var p))
{
if (p.IsWord)
{
sb.Append(first);
sb.Append(" ");
}
else
{
var index = 1;
var find = false;
for (; index < successor.Length; index++)
{
if (p.Next.TryGetValue(successor[index], out var next))
{
p = next;
if (!p.IsWord) continue;
find = true;
}
break;
}
sb.Append(find ? successor.Substring(0, index + 1) : successor);
sb.Append(" ");
}
}
else
{
sb.Append(successor);
sb.Append(" ");
}
}
}
public string ReplaceWords2(IList<string> dictionary, string sentence)
{
var setDictionary = new HashSet<string>(dictionary);
var successors = sentence.Split();
for (var i = 0; i < successors.Length; i++)
{
var successor = successors[i];
for (var j = 0; j < successor.Length; j++)
{
var subSuccessor = successor.Substring(0, j + 1);
if (!setDictionary.Contains(subSuccessor)) continue;
successors[i] = subSuccessor;
break;
}
}
return string.Join(' ', successors);
}
- LRU 缓存-mihayou
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
- LRU 缓存-mihayou
public class LinkList
{
public int Value;
public int Key;
public LinkList Pre;
public LinkList Next;
public LinkList(int key, int value)
{
Value = value;
Key = key;
}
}
public class LRUCache
{
private Dictionary<int, LinkList> __cache = new Dictionary<int, LinkList>();
private LinkList __head = null;
private LinkList __tail = null;
private int __capacity;
public LRUCache(int capacity)
{
__capacity = capacity;
//虚拟头结点以及尾节点
__head = new LinkList(-1, -1);
__tail = new LinkList(-1, -1);
__head.Next = __tail;
__tail.Pre = __head;
}
public int Get(int key)
{
if (__cache.TryGetValue(key, out var v))
{
__Update(v);
return v.Value;
}
return -1;
}
public void Put(int key, int value)
{
if (__cache.TryGetValue(key, out var linkList))
{
__Update(linkList);
linkList.Value = value;
}
else
{
//当容量满的时候,移除最后一个节点
if (__cache.Count == __capacity)
{
//__tail之前大节点才是真正大尾节点
var last = __tail.Pre;
__cache.Remove(last.Key);
var lastPre = last.Pre;
lastPre.Next = __tail;
__tail.Pre = lastPre;
}
//插入新节点,应该插在虚拟头节点的next
var next = __head.Next;
linkList = new LinkList(key, value)
{
Next = next,
};
next.Pre = linkList;
linkList.Pre = __head;
__head.Next = linkList;
}
__cache[key] = linkList;
}
private void __Update(LinkList l)
{
if (__head.Next == l)
{
return;
}
//先把原先的连接起来
var pre = l.Pre;
pre.Next = l.Next;
l.Next.Pre = pre;
//把l插入header下一个节点
var headNext = __head.Next;
headNext.Pre = l;
l.Pre = __head;
l.Next = headNext;
__head.Next = l;
}
}
- 460-LFU 缓存
请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。
实现 LFUCache 类:
LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象
int get(int key) - 如果键 key 存在于缓存中,则获取键的值,否则返回 -1 。
void put(int key, int value) - 如果键 key 已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键。
为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。
当一个键首次插入到缓存中时,它的使用计数器被设置为 1 (由于 put 操作)。对缓存中的键执行 get 或 put 操作,使用计数器的值将会递增。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
public class Node
{
public int Key;
public int Value;
public int Cnt;
public Node Pre;
public Node Next;
public Node(int key, int value)
{
Key = key;
Value = value;
Cnt = 0;
}
}
public class LFUCache
{
private Dictionary<int, Node> __cache = new Dictionary<int, Node>();
private Node __head;
private Node __tail;
private int __capacity;
public LFUCache(int capacity)
{
__capacity = capacity;
__head = new Node(-1, -1);
__tail = new Node(-1, -1);
__head.Next = __tail;
__head.Cnt = Int32.MaxValue;
__tail.Pre = __head;
__tail.Cnt = Int32.MinValue;
}
public int Get(int key)
{
if (__cache.TryGetValue(key, out var node))
{
__RefreshLinkList(node);
return node.Value;
}
return -1;
}
public void Put(int key, int value)
{
if (__capacity == 0)
{
return;
}
if (__cache.TryGetValue(key, out var node))
{
node.Value = value;
__RefreshLinkList(node);
}
else
{
if (__cache.Count == __capacity)
{
var last = __tail.Pre;
last.Pre.Next = __tail;
__tail.Pre = last.Pre;
__cache.Remove(last.Key);
}
node = new Node(key, value);
var temp = __tail.Pre;
temp.Next = node;
node.Next = __tail;
__tail.Pre = node;
node.Pre = temp;
__RefreshLinkList(node);
__cache[key] = node;
}
}
private void __RefreshLinkList(Node node)
{
node.Cnt++;
if (node.Pre.Cnt > node.Cnt)
{
return;
}
var pre = node.Pre;
pre.Next = node.Next;
node.Next.Pre = pre;
pre = __GetNode(pre, node);
var next = pre.Next;
node.Next = next;
pre.Next = node;
next.Pre = node;
node.Pre = pre;
}
private Node __GetNode(Node pre, Node cur)
{
var tempHead = __head;
while (true)
{
if (pre.Cnt <= cur.Cnt)
{
pre = pre.Pre;
}
else
{
return pre;
}
if (tempHead.Cnt > cur.Cnt)
{
tempHead = tempHead.Next;
}
else
{
return tempHead.Pre;
}
}
}
}
双向链表
public class LFUCache2
{
class DoubleLinkList
{
public int Cnt;
public Node Head;
public Node Tail;
public DoubleLinkList(int cnt)
{
Head = new Node(-1, -1);
Tail = new Node(-1, -1);
Head.Next = Tail;
Tail.Pre = Head;
Cnt = cnt;
}
public void Add(Node node)
{
var next = Head.Next;
node.Next = next;
Head.Next = node;
next.Pre = node;
node.Pre = Head;
}
public void Remove(Node node)
{
var pre = node.Pre;
pre.Next = node.Next;
node.Next.Pre = pre;
}
}
private Dictionary<int, Node> __cache = new Dictionary<int, Node>();
private Dictionary<int, DoubleLinkList> __cacheCnt = new Dictionary<int, DoubleLinkList>();
private int __capacity;
private int __minCnt;
public LFUCache2(int capacity)
{
__capacity = capacity;
__minCnt = 1;
}
public int Get(int key)
{
if (__capacity == 0)
{
return -1;
}
if (__cache.TryGetValue(key, out var node))
{
__UpdateCnt(node);
return node.Value;
}
return -1;
}
public void Put(int key, int value)
{
if (__capacity == 0)
{
return;
}
if (__cache.TryGetValue(key, out var node))
{
node.Value = value;
__UpdateCnt(node);
}
else
{
if (__cache.Count == __capacity)
{
if (__cacheCnt.TryGetValue(__minCnt, out var doubleList) && doubleList.Head.Next != doubleList.Tail)
{
var t = doubleList.Tail.Pre;
__cache.Remove(t.Key);
t.Pre.Next = doubleList.Tail;
doubleList.Tail.Pre = t.Pre;
}
}
node = new Node(key, value);
node.Cnt++;
__InsertNode(node);
__cache[key] = node;
__minCnt = 1;
}
}
private void __UpdateCnt(Node node)
{
if (__cacheCnt.TryGetValue(node.Cnt, out var linkList))
{
linkList.Remove(node);
if (__minCnt == node.Cnt && linkList.Head.Next == linkList.Tail)
{
__minCnt++;
}
}
node.Cnt++;
__InsertNode(node);
}
private void __InsertNode(Node node)
{
if (__cacheCnt.TryGetValue(node.Cnt, out var linkList))
{
linkList.Add(node);
}
else
{
linkList = new DoubleLinkList(node.Cnt);
linkList.Add(node);
__cacheCnt[node.Cnt] = linkList;
}
}
}