我在互联网上遇到了以下面试问题。
描述getValue(int index),setValue(int index,int value)和setAllValues(int value)都是O(1)的数据结构。
虽然数组足以让第一次和第二次操作在O(1)中执行,但第三次(setAllValues)可以提出什么呢?
答案 0 :(得分:45)
array
个元组{timestamp, value}
如何,其他{timestamp, value}
名为all
。由于您只关心插入的相对时间,因此可以使用单调递增的id
作为时间戳的值:
type Entry {
int timestamp,
int value
}
type structure {
int id
Entry all
Entry[] array
}
将所有字段初始化为0.然后以下内容适用于您:
setValue(index i,value v):
array[i] = {id++, value}
value getValue(index i)
if(all.timestamp > array[i].timestamp) return all.value
else return array[i].value
setAll(value v)
all = {id++, value}
这种方法的一个问题是,最终你会用掉时间戳的id,并且可能会回滚。如果您选择64位值来存储时间戳,那么在此之前,这将为您提供18,446,744,073,709,551,616次插入或setAlls。根据数据结构的预期用途,O(n)清理阶段可能是合适的,或者您可以抛出异常。
可能需要考虑的另一个问题是多线程。三个明显的问题:
id++
不是原子的,并且两个线程同时获得了新的id
,那么您可以获得两个具有相同ID的条目。insert()
与get()
同时存在{new_id, old_value}
那么你最终可能会说到{{1}在数组中,导致返回错误的值。如果这些问题中的任何一个是问题,那么绝对最简单的解决办法是在文档中使用“not thread safe”(作弊)。或者,如果您无法以您选择的语言原子地实现这些方法,则需要在它们周围放置某种同步锁。
答案 1 :(得分:6)
我在其中一次技术访谈中得到了同样的问题 这是我完整的即用型Java实现,包括测试用例。
关键的想法是将setAll()
的值保留在特殊变量(例如joker
)中,然后以适当的方式跟踪此值的更改。
为了保持代码清洁,一些访问修饰符已被废除。
节点 类:
import java.time.LocalDate;
class Node {
int value;
LocalDate jokerSetTime;
Node(int val, LocalDate jokSetTime) {
value = val;
jokerSetTime = jokSetTime;
}
}
DS 类:
class DS {
Node[] arr;
DS(int len) {
arr = new Node[len];
}
}
DataStructure 类:
import java.time.LocalDate;
class DataStructure {
private boolean isJokerChanged;
private Integer joker;
private LocalDate jokerSetTime;
private DS myDS;
DataStructure(int len) {
myDS = new DS(len);
}
Integer get(int i) {
Integer result;
if (myDS.arr.length < i) {
return null;
}
// setAll() has been just called
if (isJokerChanged) {
return joker;
}
if (myDS.arr[i] == null) {
// setAll() has been previously called
if (joker != null) {
result = joker;
} else {
result = null;
}
} else if (myDS.arr[i].jokerSetTime == jokerSetTime) {
// cell value has been overridden after setAll() call
result = myDS.arr[i].value;
} else {
result = joker;
}
return result;
}
void setAll(int val) {
isJokerChanged = true;
joker = val;
jokerSetTime = LocalDate.now();
}
void set(int i, int val) {
isJokerChanged = false;
myDS.arr[i] = new Node(val, jokerSetTime);
}
}
主要 类:
class Main {
public static void main(String[] args) {
DataStructure ds = new DataStructure(100);
Integer res;
res = ds.get(3);
ds.set(3, 10);
res = ds.get(3);
ds.setAll(6);
res = ds.get(3);
res = ds.get(15);
ds.set(4, 7);
res = ds.get(4);
res = ds.get(3);
ds.setAll(6);
ds.set(8, 2);
res = ds.get(3);
}
}
<强>更新强>
代码已更新。之前的实现没有考虑到setAll()
连续两次调用具有相同值并且后跟set(x)
,get(y)
的情况,例如:{{1 }},setAll(100)
,set(3, 1)
,setAll(100)
,set(5, 3)
。
添加了时间戳方法,以便区分具有相同值的不同get(3)
个调用。
P.S。此实现不是线程安全的。
答案 2 :(得分:5)
指向单个公共值的指针数组怎么样?设置值,所有引用都将指向O(1)中的单个更改值。
答案 3 :(得分:3)
我刚刚在面试中被问到这个问题。我想出了一个哈希表实现。它可以解决耗尽时间戳值的问题,但需要实现线程安全功能(可能使用延迟初始化技术)
我们在课堂上说我们有一个私有变量 _defaultValue 来保存默认值,我们还有一个私有哈希表或字典 _hashtable 。 SetAllValues 可以将 _defaultValue 设置为等于传递的值,并将 _hashtable 初始化/设置为新的哈希表,并放弃对旧哈希表的任何引用。 SetValue 应该只为 _hashtable 添加新值,或者如果 _hashtable 中已存在键(或索引),则更新该值。 GetValue 应检查 _hashtable 中是否存在键(或索引),然后返回,否则返回存储在 _defaultValue 中的值。
这是我在StackOverflow上的第一个答案。我在编写代码时有点懒惰。很可能会很快编辑答案。
面试官对此解决方案表示赞同,但坚持在不使用哈希表的情况下实施该解决方案。我想,他要我提出类似Timothy的回答。那一刻我无法得到它:(无论如何,干杯!
编辑: 发布代码(在C#中)
class MyDataStruct
{
private int _defaultValue;
private Dictionary<int,int> _hashtable;
public MyDataStruct()
{
_defaultValue = 0; // initialize default with some value
_hashtable = new Dictionary<int, int>();
}
public void SetAllValues(int val)
{
_defaultValue = val;
_hashtable = new Dictionary<int, int>();
}
public void SetValue(int index, int val)
{
if (_hashtable.ContainsKey(index))
{
_hashtable.Add(index, val);
}
else
{
_hashtable[index] = val;
}
}
public int GetValue(int index)
{
if (_hashtable.ContainsKey(index))
{
return _hashtable[index];
}
else
{
return _defaultValue;
}
}
}
答案 4 :(得分:2)
我们可以有一个变量V,它存储一个int,一个包含元组的数组为{Value,id} ..
一个全局的int变量G(在SQL中就像身份一样,每当完成任何set或setAll操作时,它的值都会增加1)
初始所有Ids和V值将默认为null ..
so V = null All Tuple = {null, null}
set(index i, val v) -> G = G+1, arr[i].Val = v, arr[i].Id = G
get(index i) -> if V.Id > arr[i].Id return V.Val else return arr[i]
set-all(val v) -> G= G+1, V.Id= G, V.Val = v
答案 5 :(得分:1)
所有现有答案都使用在每setVal
次操作时递增的时间戳。这不是必需的。实际上,只需要增加setAll
上的时间戳。有人提出的另一个问题是算术溢出。通过更新每个setAll
上的单个单元格并仔细执行时间比较,可以在不中断常数时间范围的情况下处理此问题。
基本概念基本上与其他答案相似,但有一个转折点。
他们做什么:分别存储用于上一次setAll
操作的值,并跟踪执行操作的时间。每次执行setVal
时,它们都会将当前时间与给定值一起存储在数组中。每次执行getVal
时,他们会将给定位置的时间与上次setAll
发生的时间进行比较,然后选择位置的值或setAll
值,具体取决于哪个更大。
为什么这可能是个问题:假设当前时间溢出并且很快就会发生setAll
操作。当它们实际上较旧时,似乎大多数存储的数组值都比setAll
值更新。
解决方案:停止想象我们正在跟踪自数据结构初始化以来已经过去的总时间。设想一个带有&#34;秒针的巨型时钟&#34;在圆圈周围不是60次,而是围绕圆圈2 ^ n次。秒针的位置表示最近setAll
操作的时间。每个setVal
操作都会将此时间与值一起存储。因此,如果我们在&#34;时钟&#34;时执行setAll
在45,然后对不同的元素执行六次setVal
操作,setAll
时间和所有六个位置的时间将是相同的。我们希望保持以下不变量:
给定元素位置的时间等于
setAll
时间,当且仅当该元素的设置比最后setVal
操作最近setAll
时才好。
显然,上述过程会自动确保如果最近设置了元素,那么它的时间将等于setAll
时间。面临的挑战是保持反向意义。
继续......
我已经在Haskell中写过这个,因为这是我最熟悉的语言,但它并不是这项工作最自然的语言。
{-# LANGUAGE BangPatterns #-}
module RepArr where
import Control.Monad.Primitive
import Data.Primitive.MutVar
import qualified Data.Vector.Mutable as V
import Data.Vector.Mutable (MVector)
import Control.Applicative
import Prelude hiding (replicate)
import Control.Monad.ST
import Data.Word
-- The Int in the MutVar is the refresh pointer
data RepArr s a = RepArr (MutVar s (Word, a, Int)) (MVector s (Word,a))
-- Create a fancy array of a given length, initially filled with a given value
replicate :: (PrimMonad m, Applicative m) => Int -> a -> m (RepArr (PrimState m) a)
replicate n a = RepArr <$> newMutVar (0,a,0) <*> V.replicate n (0,a)
getVal :: PrimMonad m => RepArr (PrimState m) a -> Int -> m a
getVal (RepArr allv vec) n = do
(vectime, vecval) <- V.read vec n
(alltime, allval, _) <- readMutVar allv
if (fromIntegral (alltime - vectime) :: Int) > 0
then return allval
else return vecval
setVal :: PrimMonad m => RepArr (PrimState m) a -> Int -> a -> m ()
setVal (RepArr allv vec) i v = do
(!alltime, _, _) <- readMutVar allv
V.write vec i (alltime, v)
setAll :: PrimMonad m => RepArr (PrimState m) a -> a -> m ()
setAll r@(RepArr allv vec) v = do
(oldt, _, oldc) <- readMutVar allv
getVal r oldc >>= setVal r oldc
let !newc = case oldc+1 of
op1 | op1 == V.length vec -> 0
| otherwise -> op1
let !newt = oldt+1
writeMutVar allv (newt, v, newc)
为了避免潜在的(罕见的)垃圾收集暂停,实际需要取消Int
和Word
值,以及使用未装箱的向量而不是多态向量,但是我&# 39;我的心情并不真实,这是一项相当机械的任务。
这是C中的一个版本(完全未经测试):
#include <malloc.h>
struct Pair {
unsigned long time;
void* val;
};
struct RepArr {
unsigned long allT;
void* allV;
long count;
long length;
struct Pair vec[];
};
struct RepArr *replicate (long n, void* val) {
struct RepArr *q = malloc (sizeof (struct RepArr)+n*sizeof (struct Pair));
q->allT = 1;
q->allV = val;
q->count = 0;
q->length = n;
int i;
for (i=0; i<n; i++) {
struct Pair foo = {0,val};
q->vec[i] = foo;
}
return q;
}
void* getVal (struct RepArr *q, long i) {
if ((long)(q->vec[i].time - q->allT) < 0)
return q->allV;
else
return q->vec[i].val;
}
void setVal (struct RepArr *q, long i, void* val) {
q->vec[i].time = q->allT;
q->vec[i].val = val;
}
void setAll (struct RepArr *q, void* val) {
setVal (q, q->count, getVal (q, q->count));
q->allV = val;
q->allT++;
q->count++;
if (q->count == q->length)
q->count = 0;
}
答案 6 :(得分:1)
/*
在我撰写本文时,此页面上的所有解决方案都会翻倍(或 更多)存储阵列所需的空间量。以下解决方案 将浪费的空间量从Ω(n)减少到θ(n / w),其中w是数量 计算机中的位“字”。在我的机器上,那是64。
这个散文在这个答案中是在C评论中,所以你可以复制并粘贴这个 逐字回答并用C编译器编译。
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
/*
问题是支持在O(1)时间内在数组中读取和写入值 以及批量写入,其中数组中的所有值一次写入 O(1)时间。这可以使用Aho,Hopcroft和 据我所知,乌尔曼。我将提供一个由Gonzalo Navarro, "Constant-Time Array Initialization in Little Space"提供的版本。
这个想法是保留三个元数据数组和数据数组。我们也
保留两个整数:unset
,这是批量写入中使用的最后一个值
操作,size
,已经过的值的近似值
自上次批量写入后设置。在任何时候,不同值的数量
自上次批量撰写以来编写的文字介于size
和w * size
之间。
三个元数据数组描述了有关w值的块的信息 数据数组。他们是:
nth
:nth [i]是自上次批量以来要写入的第i个唯一块
写
inverse_nth
:inverse_nth [i]是其中第i个块的顺序
数组是在最后一次批量写入时从0开始计算的。
bitset
:当数组单元编号时,bitset[i]
的第j位为1
自上次批量写入以来已写入64 * i + j。
bitset[i]
不是,则{p> inverse_nth[i]
和i
将被视为无效
集{nth[0]
,nth[1]
,...,nth[size-1]
}的成员。换一种说法,
当且仅当inverse_nth[i]
时,bitset[i]
和inverse_nth[i] < size
才有效
和nth[inverse_nth[i]] == i
。
我没有存储三个相同长度的独立数组,而是选择存储一个
数组,is_set
,有三个字段。
*/
typedef struct {
int nth_;
int inverse_nth_;
uint64_t bitset_;
} IsSetCell;
typedef struct {
int unset_;
int size_;
IsSetCell is_set_[];
} IsSetArray;
typedef struct {
IsSetArray * metadata_;
int payload_[];
} ResettableArray;
/*
要构造一个数组,我们需要一个默认值来在读取时返回 从未写过的价值。
*/
ResettableArray * ConstructResettableArray(int n, int unset) {
ResettableArray* result =
malloc(offsetof(ResettableArray, payload_) + n * sizeof(int));
if (!result) return NULL;
n = (n + 63) / 64;
result->metadata_ =
malloc(offsetof(IsSetArray, is_set_) + n * sizeof(IsSetCell));
if (!result->metadata_) {
free(result);
return NULL;
}
result->metadata_->size_ = 0;
result->metadata_->unset_ = unset;
return result;
}
void DestructResettableArray(ResettableArray * a) {
if (a) free(a->metadata_);
free(a);
}
/*
大部分算法都是写作和阅读元数据。后
定义IsSet()
和Set()
(下面),读取和写入数组
简单。
*/
bool IsSet(const IsSetArray * a, int i);
void Set(IsSetArray * a, int i);
int GetValue(const ResettableArray * a, int i) {
if (!IsSet(a->metadata_, i)) return a->metadata_->unset_;
return a->payload_[i];
}
void SetValue(ResettableArray * a, int i, int v) {
a->payload_[i] = v;
Set(a->metadata_, i);
}
void SetAllValues(ResettableArray * a, int v) {
a->metadata_->unset_ = v;
}
/*
阅读和写作的复杂部分是双向关系
在inverse_nth
和nth
之间。如果他们在位置i指向对方
(is_set[is_set[i].inverse_nth].nth == i
)然后位置i包含有效数据
这是在最后一次批量写入后编写的,只要is_set[i].inverse_nth <
size
。
*/
uint64_t OneBit(int i) {
return UINT64_C(1) << i;
}
bool IsSet(const IsSetArray * a, int i) {
const int cell = i/64, offset = i & 63;
const int inverse_nth = a->is_set_[cell].inverse_nth_;
return inverse_nth < a->size_ && a->is_set_[inverse_nth].nth_ == cell &&
a->is_set_[cell].bitset_ & OneBit(offset);
}
void Set(IsSetArray * a, int i) {
const int cell = i/64, offset = i & 63;
const int inverse_nth = a->is_set_[cell].inverse_nth_;
if (inverse_nth >= a->size_ || a->is_set_[inverse_nth].nth_ != cell) {
a->is_set_[cell].inverse_nth_ = a->size_;
a->is_set_[cell].bitset_ = 0;
a->is_set_[a->size_].nth_ = cell;
++a->size_;
}
a->is_set_[cell].bitset_ |= OneBit(offset);
}
答案 7 :(得分:0)
这是另一个python解决方案: 这是a link!
from datetime import datetime
from typing import Any, Dict
class ValueNode:
def __init__(self, value):
self.value = value
self.date_updated = datetime.now()
def set_value(self, value):
self.value = value
self.date_updated = datetime.now()
def get_value(self, value):
return self.value
class Structure:
def __init__(self):
self._structure: Dict[Any, ValueNode] = {}
self._set_all_node: ValueNode = None
def get_val(self, index):
if self._set_all_node and self._structure.get(index) and self._structure.get(index).date_updated < self._set_all_node.date_updated:
return self._set_all_node.value
else:
if index in self._structure:
return self._structure[index].value
else:
return None
def set_val(self, index, value):
self._structure[index] = ValueNode(value)
def set_all(self, value):
self._set_all_node = ValueNode(value)
s1 = Structure()
s1.set_val(1, 'green')
s1.set_val(5, 'blue')
s1.set_val(9, 'yellow')
print(s1.get_val(1))
print(s1.get_val(5))
print(s1.get_val('NotExistedValue'))
s1.set_all('black')
print(s1.get_val(1))
print(s1.get_val(5))
print(s1.get_val('NotExistedValue'))
答案 8 :(得分:0)
我的 Python 解决方案。测试。不是线程安全的。 如果您发现任何问题,请告诉我:)
class TimestampedNode:
def __init__(self, timestamp, val):
self.timestamp = timestamp
self.val = val
class SetAllDS:
def __init__(self):
self.items = []
self.timestamp = 0
self.all_joker= TimestampedNode(self.timestamp, 0)
def getValue(self, index):
try:
item=self.items[index]
except IndexError:
return None
if item.timestamp<self.all_joker.timestamp:
return self.all_joker.val
return item.val
def setValue(self, index, val):
# if index<0 or index>=len(self.items): #
# raise IndexError("Invalid index\n")
self.timestamp += 1
self.items[index]=TimestampedNode(self.timestamp, val)
def setAllValues(self, val):
self.timestamp+=1
self.all_joker=TimestampedNode(self.timestamp, val)
答案 9 :(得分:0)
许多解决方案都很棒,但是没有一个提到state-of-the-art一个解决方案。
对于fill(v), read(i), write(i, v)
操作,它具有 O(1)最坏时间复杂度
(调用 fill(v)会将数组中的所有值设置为v,并且 read / write 是不言自明的),
在阵列之外仅占用 1位额外空间。是的
因此,大小为1,000,000的int32_t数组将花费O(1)最坏的时间进行初始化(并填充),
并且仅占用32,000,001位内存。
In-Place Initializable Arrays论文中有提及,
我写过关于该主题的Article中对此有解释。
我写了一个名为Farray的C ++头文件库,该库具有 F 可操作的 Array ,
这是上面论文的模板实现。
答案 10 :(得分:0)
嗯,我是根据事件来做的。看看。
internal class Program
{
public static void Main(string[] args)
{
SomeUsefullDataStructure ds = new SomeUsefullDataStructure();
ds.SetValue(1, "11");
ds.SetValue(2, "22");
var result = ds.GetValue(2);
ds.SetAllValues("haha");
Console.ReadKey();
}
}
public class SomeUsefullDataStructure
{
private delegate void SetValueDelegate(string newValue);
private event SetValueDelegate SetValueEventFired;
private Dictionary<int, StringDataEntry> dict = new Dictionary<int, StringDataEntry>();
public string GetValue(int key)
{
if (dict.ContainsKey(key))
{
return dict[key].StringValue;
}
throw new ArgumentException("no such key");
}
public void SetValue(int key, string value)
{
if (dict.ContainsKey(key))
{
dict[key].UpdateValue(value);
}
else
{
StringDataEntry stringDataEntry = new StringDataEntry(value);
SetValueEventFired += stringDataEntry.UpdateValue;
dict.Add(key, stringDataEntry);
}
}
public void SetAllValues(string value)
{
SetValueEventFired(value);
}
}
public class StringDataEntry
{
public string StringValue { get; private set; }
public StringDataEntry(string value)
{
StringValue = value;
}
public void UpdateValue(string newValue)
{
StringValue = newValue;
}
}
答案 11 :(得分:0)
我在C#中针对此问题的实现:
public class MyStruct
{
public MyStruct(int val)
{
this.value = val;
this.currentTime = 0;
}
public int value { get; set; }
public int currentTime { get; set; }
}
public class Struct
{
public List<MyStruct> array = new List<MyStruct>();
public MyStruct all = new MyStruct(0);
public int GetValue(int index)
{
if(all.currentTime >= array[index].currentTime)
{
return all.value;
}
else
{
return array[index].value;
}
}
public void Set(int index, int value)
{
if(array.Count <= index)
{
array.Add(new MyStruct(value));
}
else
{
array[index].value = value;
}
array[index].currentTime = all.currentTime +1;
}
public void SetAll(int value)
{
all.value = value;
all.currentTime++;
}
public void Delete(int index)
{
array[index].currentTime = 0;
array[index].value = -1;
}
}
陈鲁加斯
答案 12 :(得分:0)
另一个Python示例:
class SetAll:
def __init__(self):
self.mapping = {}
self.is_all_same = True
self.all_value = None
self.set_all_ran = False
def set(self, index, value):
if self.is_all_same:
if value == self.all_value:
return
else:
self.is_all_same = False
self.mapping[index] = value
else:
self.mapping[index] = value
def get(self, index):
if self.mapping.get(index, None):
return self.mapping[index]
else:
if self.is_all_same:
return self.all_value
else:
if self.set_all_ran:
return self.all_value
return
def set_all(self, value):
self.mapping = {}
self.is_all_same = True
self.set_all_ran = True
self.all_value = value
答案 13 :(得分:0)
我最近也遇到了类似的问题。我使用的数据结构是哈希映射和哈希集的组合。
1)setValue(字符串键,字符串值) 在这种方法中,我直接将对插入到哈希图中。我们还将密钥插入哈希集中
2)setAllValue(字符串值) 在这种方法中,我重新初始化哈希图。这将所有配对删除,然后添加一个键,例如<“ god”>和值。 哈希集具有在所有版本的哈希图中维护的键集。
3)getValue(字符串键) 在这种方法中,我维护多个if / else条件来返回值。
OptimizedMap类{
Map<String, String> mymap = new HashMap<String>();
Set<String> myset = new HashSet<>();
public void setValue (String key, String value) {
mymap.put(key, value);
myset.add(key);
}
public void setAllValue (String value) {
mymap = new HashMap<>();
mymap.put("god", value);
}
public String getValue (String key) {
if (mymap.containsKey(key)) {
return mymap.get(key);
} else if (!myset.contains(key)) {
return null;
} else {
return mymap.get(key);
}
}
public static void main (String args[]) {
OptimisedMap opmap = new OptimisedMap();
String value = opmap.getValue("hey");
if (value == null) {
System.out.println("Key not present");
}
opmap.setValue("hey", "there");
opmap.setValue("ho", "there");
System.out.println(opmap.getValue("hey")); // will print there
opmap.setAllValue("whatsup");
System.out.println(opmap.getValue("hey")); // will print whatsup
System.out.println(opmap.getValue("ho")); // will print whatsup
opmap.setValue("hey", "there");
System.out.println(opmap.getValue("hey")); // will print there
System.out.println(opmap.getValue("ho")); // will print whatsup
}
}
答案 14 :(得分:0)
这是我在Java中的答案(我不完全确定语法)。 我将set-functions同步,以避免changeT和defChangeT相等的情况。
Struct ValueSt{
int value;
Timestamp changeT;
}
Class MyDS{
int default;
Timestamp defChangeT;
HashMap map;
public MyDS(){
map = new HashMap<int, ValueSt>();
}
public synchronized void mySet(Int key, int value){
ValueSt vs = new ValueSt(value, Timestamp(System.current));
map.put(key, vs);
}
public synchronized void setAll(int value){
default = value;
defChangeT = Timestamp(System.current));
}
public int myGet(int key){
ValueSt vs = map.get(key);
if(vs != null){
if(vs.changeT > defChangeT)
return vs.value;
else
return default;
}
return null;
}
}
答案 15 :(得分:0)
关于Timothy Jone的回答:
这种方法的一个问题是,最终你会用掉时间戳的id,并且可能会回滚。如果您选择64位值来存储时间戳,那么在此之前,这将为您提供18,446,744,073,709,551,616次插入或setAlls。根据数据结构的预期用途,O(n)清理阶段可能是合适的,或者您可以抛出异常。
这正是最糟糕的情况,这个解决方案也是O(n),而不是O(1)。这种结构虽然节省了大量潜在的O(n)插入操作,但仍处于O(n)效率。
答案 16 :(得分:0)
Python示例
class d:
def __init__(self, l):
self.len = l
self.g_p = [i for i in range(self.len)]
self.g_v = [0 for i in range(self.len)]
self.g_s = self.len - 1
self.g_c = 0
def getVal(self, i):
if (i < 0 or i >= self.len):
return
if (self.g_p[i] <= self.g_s):
return self.g_v[self.g_p[i]]
return self.g_c
def setVal(self, i, v):
if (i < 0 or i >= self.len):
return
if (self.g_p[i] > self.g_s):
self.g_s += 1
self.g_p[self.g_s], self.g_p[i] = self.g_p[i], self.g_p[self.g_s]
self.g_v[self.g_p[i]] = v
def setAll(self, v):
self.g_c = v
self.g_s = -1
答案 17 :(得分:-1)
C#中的正确解决方案:
public sealed class SpecialDictionary<T, V>
{
private Dictionary<T, Tuple<DateTime, V>> innerData;
private Tuple<DateTime, V> setAllValue;
private DateTime prevTime;
public SpecialDictionary()
{
innerData = new Dictionary<T, Tuple<DateTime, V>>();
}
public void Set(T key, V value) => innerData[key] = new Tuple<DateTime, V>(GetTime(), value);
public void SetAll(V value) => setAllValue = new Tuple<DateTime, V>(GetTime(), value);
public V Get(T key)
{
Tuple<DateTime, V> tmpValue = innerData[key];
if (setAllValue?.Item1 > tmpValue.Item1)
{
return setAllValue.Item2;
}
else
{
return tmpValue.Item2;
}
}
private DateTime GetTime()
{
if (prevTime == null)
{
prevTime = DateTime.Now;
}
else
{
if (prevTime == DateTime.Now)
{
Thread.Sleep(1);
}
prevTime = DateTime.Now;
}
return prevTime;
}
}
测试:
static void Main(string[] args)
{
SpecialDictionary<string, int> dict = new SpecialDictionary<string, int>();
dict.Set("testA", 1);
dict.Set("testB", 2);
dict.Set("testC", 3);
Console.WriteLine(dict.Get("testC"));
dict.SetAll(4);
dict.Set("testE", 5);
Console.WriteLine(dict.Get("testC"));
Console.WriteLine(dict.Get("testE"));
Console.ReadKey();
}