comments | difficulty | edit_url | rating | source | tags | ||||
---|---|---|---|---|---|---|---|---|---|
true |
中等 |
1479 |
第 7 场双周赛 Q2 |
|
你需要设计一个文件系统,你可以创建新的路径并将它们与不同的值关联。
路径的格式是一个或多个连接在一起的字符串,形式为: /
,后面跟着一个或多个小写英文字母。例如, " /leetcode"
和 "/leetcode/problems"
是有效路径,而空字符串 ""
和 "/"
不是。
实现 FileSystem
类:
bool createPath(string path, int value)
创建一个新的path
,并在可能的情况下关联一个value
,然后返回true
。如果路径已经存在或其父路径不存在,则返回false
。-
int get(string path)
返回与path
关联的值,如果路径不存在则返回-1
。
示例 1:
输入: ["FileSystem","create","get"] [[],["/a",1],["/a"]] 输出: [null,true,1] 解释: FileSystem fileSystem = new FileSystem(); fileSystem.create("/a", 1); // 返回 true fileSystem.get("/a"); // 返回 1
示例 2:
输入: ["FileSystem","createPath","createPath","get","createPath","get"] [[],["/leet",1],["/leet/code",2],["/leet/code"],["/c/d",1],["/c"]] 输出: [null,true,true,2,false,-1] 解释: FileSystem fileSystem = new FileSystem(); fileSystem.createPath("/leet", 1); // 返回 true fileSystem.createPath("/leet/code", 2); // 返回 true fileSystem.get("/leet/code"); // 返回 2 fileSystem.createPath("/c/d", 1); // 返回 false 因为父路径 "/c" 不存在。 fileSystem.get("/c"); // 返回 -1 因为该路径不存在。
提示:
- 对两个函数的调用次数加起来小于等于
104
2 <= path.length <= 100
1 <= value <= 109
我们可以使用前缀树来存储路径,每个节点存储一个值,表示该节点对应的路径的值。
定义前缀树的节点结构如下:
children
:子节点,使用哈希表存储,键为子节点的路径,值为子节点的引用;v
:当前节点对应的路径的值。
定义前缀树的方法如下:
-
insert(w, v)
:插入路径$w$ ,并将其对应的值设为$v$ 。如果路径$w$ 已经存在或其父路径不存在,则返回false
,否则返回true
。时间复杂度为$O(|w|)$ ,其中$|w|$ 为路径$w$ 的长度; -
search(w)
:返回路径$w$ 对应的值。如果路径$w$ 不存在,则返回$-1$ 。时间复杂度为$O(|w|)$ 。
总时间复杂度
class Trie:
def __init__(self, v: int = -1):
self.children = {}
self.v = v
def insert(self, w: str, v: int) -> bool:
node = self
ps = w.split("/")
for p in ps[1:-1]:
if p not in node.children:
return False
node = node.children[p]
if ps[-1] in node.children:
return False
node.children[ps[-1]] = Trie(v)
return True
def search(self, w: str) -> int:
node = self
for p in w.split("/")[1:]:
if p not in node.children:
return -1
node = node.children[p]
return node.v
class FileSystem:
def __init__(self):
self.trie = Trie()
def createPath(self, path: str, value: int) -> bool:
return self.trie.insert(path, value)
def get(self, path: str) -> int:
return self.trie.search(path)
# Your FileSystem object will be instantiated and called as such:
# obj = FileSystem()
# param_1 = obj.createPath(path,value)
# param_2 = obj.get(path)
class Trie {
Map<String, Trie> children = new HashMap<>();
int v;
Trie(int v) {
this.v = v;
}
boolean insert(String w, int v) {
Trie node = this;
var ps = w.split("/");
for (int i = 1; i < ps.length - 1; ++i) {
var p = ps[i];
if (!node.children.containsKey(p)) {
return false;
}
node = node.children.get(p);
}
if (node.children.containsKey(ps[ps.length - 1])) {
return false;
}
node.children.put(ps[ps.length - 1], new Trie(v));
return true;
}
int search(String w) {
Trie node = this;
var ps = w.split("/");
for (int i = 1; i < ps.length; ++i) {
var p = ps[i];
if (!node.children.containsKey(p)) {
return -1;
}
node = node.children.get(p);
}
return node.v;
}
}
class FileSystem {
private Trie trie = new Trie(-1);
public FileSystem() {
}
public boolean createPath(String path, int value) {
return trie.insert(path, value);
}
public int get(String path) {
return trie.search(path);
}
}
/**
* Your FileSystem object will be instantiated and called as such:
* FileSystem obj = new FileSystem();
* boolean param_1 = obj.createPath(path,value);
* int param_2 = obj.get(path);
*/
class Trie {
public:
unordered_map<string, Trie*> children;
int v;
Trie(int v) {
this->v = v;
}
bool insert(string& w, int v) {
Trie* node = this;
auto ps = split(w, '/');
for (int i = 1; i < ps.size() - 1; ++i) {
auto p = ps[i];
if (!node->children.count(p)) {
return false;
}
node = node->children[p];
}
if (node->children.count(ps.back())) {
return false;
}
node->children[ps.back()] = new Trie(v);
return true;
}
int search(string& w) {
Trie* node = this;
auto ps = split(w, '/');
for (int i = 1; i < ps.size(); ++i) {
auto p = ps[i];
if (!node->children.count(p)) {
return -1;
}
node = node->children[p];
}
return node->v;
}
private:
vector<string> split(string& s, char delim) {
stringstream ss(s);
string item;
vector<string> res;
while (getline(ss, item, delim)) {
res.emplace_back(item);
}
return res;
}
};
class FileSystem {
public:
FileSystem() {
trie = new Trie(-1);
}
bool createPath(string path, int value) {
return trie->insert(path, value);
}
int get(string path) {
return trie->search(path);
}
private:
Trie* trie;
};
/**
* Your FileSystem object will be instantiated and called as such:
* FileSystem* obj = new FileSystem();
* bool param_1 = obj->createPath(path,value);
* int param_2 = obj->get(path);
*/
type trie struct {
children map[string]*trie
v int
}
func newTrie(v int) *trie {
return &trie{map[string]*trie{}, v}
}
func (t *trie) insert(w string, v int) bool {
node := t
ps := strings.Split(w, "/")
for _, p := range ps[1 : len(ps)-1] {
if _, ok := node.children[p]; !ok {
return false
}
node = node.children[p]
}
if _, ok := node.children[ps[len(ps)-1]]; ok {
return false
}
node.children[ps[len(ps)-1]] = newTrie(v)
return true
}
func (t *trie) search(w string) int {
node := t
ps := strings.Split(w, "/")
for _, p := range ps[1:] {
if _, ok := node.children[p]; !ok {
return -1
}
node = node.children[p]
}
return node.v
}
type FileSystem struct {
trie *trie
}
func Constructor() FileSystem {
return FileSystem{trie: newTrie(-1)}
}
func (this *FileSystem) CreatePath(path string, value int) bool {
return this.trie.insert(path, value)
}
func (this *FileSystem) Get(path string) int {
return this.trie.search(path)
}
/**
* Your FileSystem object will be instantiated and called as such:
* obj := Constructor();
* param_1 := obj.CreatePath(path,value);
* param_2 := obj.Get(path);
*/
class Trie {
children: Map<string, Trie>;
v: number;
constructor(v: number) {
this.children = new Map<string, Trie>();
this.v = v;
}
insert(w: string, v: number): boolean {
let node: Trie = this;
const ps = w.split('/').slice(1);
for (let i = 0; i < ps.length - 1; ++i) {
const p = ps[i];
if (!node.children.has(p)) {
return false;
}
node = node.children.get(p)!;
}
if (node.children.has(ps[ps.length - 1])) {
return false;
}
node.children.set(ps[ps.length - 1], new Trie(v));
return true;
}
search(w: string): number {
let node: Trie = this;
const ps = w.split('/').slice(1);
for (const p of ps) {
if (!node.children.has(p)) {
return -1;
}
node = node.children.get(p)!;
}
return node.v;
}
}
class FileSystem {
trie: Trie;
constructor() {
this.trie = new Trie(-1);
}
createPath(path: string, value: number): boolean {
return this.trie.insert(path, value);
}
get(path: string): number {
return this.trie.search(path);
}
}
/**
* Your FileSystem object will be instantiated and called as such:
* var obj = new FileSystem()
* var param_1 = obj.createPath(path,value)
* var param_2 = obj.get(path)
*/