赞
踩
哈希表+双向链表,保证可以随时在头结点和尾节点进行数据插删除,同时记得更新dict哈希表中存储的key值
最新使用的程序插在双向链表的头部。
- class DLinkedNode:
- """
- 双链表节点
- """
- def __init__(self, key: int = 0, value: int = 0):
- self.prev = None
- self.next = None
- self.key = key
- self.value = value
-
- class LRUCache:
-
- def __init__(self, capacity: int):
- self.size = 0
- self.capacity = capacity
- self.cache = dict()
- self.head = DLinkedNode()
- self.tail = DLinkedNode()
- self.head.next = self.tail
- self.tail.prev = self.head
-
- def get(self, key: int) -> int:
- # 如果key不在cache中, 直接返回-1
- if key not in self.cache:
- return -1
-
- # 从cache中获取key对应的节点
- node = self.cache[key]
- # 移动节点到链表的头部
- self.move_to_head(node)
- # 返回节点的值
- return node.value
-
- def put(self, key: int, value: int) -> None:
-
- node = DLinkedNode(key, value)
-
- # 如果key不在cache中
- if key not in self.cache:
- # 且此时缓存容量已满
- if self.capacity == self.size:
- # 移除链表中最后一个节点
- last_node = self.remove_last()
- # 同时从cache中弹出最后一个节点
- self.cache.pop(last_node.key)
- # 把新节点加入到链表的头部
- self.add_to_head(node)
- # 更新cache
- self.cache[key] = node
- else:
- # 容量未满, 直接把新节点加入到链表头部
- self.add_to_head(node)
- # 同时更新缓存
- self.cache[key] = node
- # 缓存大小加一
- self.size += 1
- else:
- # 如果key在cache中, 那就不用再考虑缓存容量的影响
- # 把老节点cache和链表中移除
- old_node = self.cache.pop(key)
- self.remove_node(old_node)
- # 再把新节点加入到cache和链表中
- self.add_to_head(node)
- self.cache[key] = node
-
- def add_to_head(self, node: DLinkedNode):
- """
- 把节点加入到链表头部
- """
- next_node = self.head.next
-
- self.head.next = node
- node.prev = self.head
-
- node.next = next_node
- next_node.prev = node
-
- def remove_node(self, node: DLinkedNode):
- """
- 从链表中移除指定节点
- """
- node.prev.next = node.next
- node.next.prev = node.prev
-
- def move_to_head(self, node: DLinkedNode):
- """
- 把节点移动到链表头部
- """
- self.remove_node(node)
- self.add_to_head(node)
-
- def remove_last(self) -> DLinkedNode:
- """
- 移除链表中最后一个节点并返回
- """
- last_node = self.tail.prev
-
- self.tail.prev.prev.next = self.tail
- self.tail.prev = self.tail.prev.prev
- return last_node
-
二倍均值法
方法实现的原理是:每次以 [最小值,红包剩余金额 / 人数 * 2] 的区间进行取值。
假设红包金额为 88.88,红包数量为 8 个,理想情况下,方法的实现效果:
第一个人领取红包金额区间为 [0.01, 88.88 / 8 * 2],即是 [0.01, 22.22] 之间随机获取金额数。假设取平均值 11.11,则剩余金额 77.77;
第二个人领取红包金额区间为 [0.01, 77.77 / 7 * 2],即是 [0.01, 22.22] 之间随机获取金额数。假设取平均值 11.11,则剩余金额 66.66;
以此类推…
- import random
- def get_packet(amount,number):
- res =[]
- person_num = number
- cur_amount = amount*100
- for _ in range(number-1):
- money = random.randint(1,cur_amount//person_num*2)
- cur_amount -= money
- person_num -= 1
- res.append(money/100)
- res.append(cur_amount/100)
- return res
-
- res = get_packet(88.88, 8)
- for amount in res:
- print('红包金额:{}'.format(amount))
如果x+x的各个数字之和得到y,就是说x是y的生成元。给出n(1<=n<=100000),求最小生成元。无解输出0.例如,n=216,121,2005时的解分别是198,0,1979.
利用打表法,提前把1到100000的最小生元给存下来,你要知道谁的最小生成元,直接输出就行了。
- #include<stdio.h>
- #define N 10005
- int a[N]
-
- int main()
- {
- int n;
- scanf("%d",&n);
-
- for(int i = 1;i<=10000;i++)
- {
- int x = i,y =i;
- while(y>0)
- {
- x += y%10;
- y/=10;
-
- }
- if (a[x] ==0)
- a[x] = i;
- }
-
- printf("%d",a[n]);
- return 0 ;
-
- }
- string = "hello world nihao world hey hello java world hi python yeoman word"
- list1 = string.split()
- set1 = set(list1)
- list2 = list(set1)
- dir2 = {}
- for i in range(len(list2)):
- dir2[list2[i]] = 0
- for j in range(len(list1)):
- if list1[j] == list2[i]:
- dir2[list2[i]]+=1
- print(dir2)
-
-
-
- ========
- from collections import Counter
- list1 = sentence.split()
- dir1 = Counter(list1)
- def sum(a,b,c,d):
- fenzi = b*c +a*d
- fenmu = a*c
-
- a =fenmu
- b =fenzi
- c = a% b
- while(c):
- a = b
- b = c
- c = a % b
- fenzi /= b
- fenmu /= b
- return fenzi,fenmu
-
- print(sum(2,1,3,1))
- def divbase(num,base):
- stack = []
- digital = "0123456789ABCDEF"
-
- while num >0:
- temp = num %base
- stack.append(temp)
- num = num//base
- #print(stack[::-1])
-
- res=""
- while stack:
- #print(stack[-1])
- if base>10:
- res +=str(digital[stack[-1]])
- stack.pop()
-
- else:
- res +=str(stack[-1])
- stack.pop()
- return res
-
- print(divbase(43,16))
---->开始时一根香两头点着,一根香只点一头,两头点着的香烧完说明过去了半小时,这时将只点了一头的香另一头也点着,从这时开始到烧完就是15分钟。
- def mySqrt(target,g):
- l = float(1)
- r = float(target)
- mid = float()
- while r-l>g:
- mid = (l+r)/2
- if mid * mid > target:
- r = mid
- else:
- l = mid
- return (l+r)/2
-
- print(mySqrt(4.1,0.001))
rand6() = {rand4() * 5 + rand4() }<=20?x/3:loop
我们可以想,第一个rand6()产生一个0~6范围的随机数a,第二个rand6()产生一个0~6范围的随机数b,如果(a, b)这一对数可以确定一个唯一的数,从而可以产生的49个数(a和b都有7种可能,则(a, b)确定的数就有7*7=49种可能)都是等概率的。这就相当于有一个二维坐标系,X轴和Y轴上都可以取0~6的数,对于取x=a,y=b可以确定一个唯一的点(a, b)。0-6生成0-9随机数
想到这个就是我们的关键,接下来就是想办法构造函数使得产生的每个数都是唯一的。我们不难想到把第一个rand6()产生的随机数a放在个位上,而把第二个rand6()产生的随机数b放在十位上,所有可能为:00~06,10~16,20~26,30~36,40~46,50~56,60~66。很容易看出这些就是7进制数,所以我们用rand6()*7+rand6()就能生成0~49范围的随机数,而且每个数产生的概率相等,都是1/49。产生40~49之间的随机数时不保留而重新产生一个新的随机数,这样产生0~39之间的数也是等概率的,仍然都是1/49,对于产生的数我们记为r(0<= r <=39),则 r/4 即可返回0~9范围的数。而且 r 取0~3这四个数时 r/4 返回0,r 取4~7这四个数时 r/4 返回1,……,r 取36~39这四个数时 r/4 返回9。因此返回0~9范围的每个数字的概率都是4/49,满足等概率。
问题描述:
五个极其聪明的海盗抢到100颗宝石,每一颗宝石都一样大小和价值连城。他们决定以抽签投票的方式来分配这些宝石:有(1、2、3、4、5)五个号码,每人抽取一个。首先,由1号提出分配方案,然后大家举手表决,当且仅当超过半数的人同意时,按照他的分配方案 进行分配,否则将被扔进海里喂鲨鱼。如果1号死后,再由2号提出分配方案,规则如前所述,以此类推。
问:第一个海盗提出怎样的分配方案才能使自己的收益最大化?为什么?
解答:https://blog.csdn.net/guo_jia_liang/article/details/53957393
答案分析: 1号海盗分给3号1枚金币,4号或5号2枚金币,自己则独得97枚金币,即分配方案为(97,0,1,2,0)或(97,0,1,0,2)。
---->抛两次,先正后反A喝,先反后正B喝
某一次抛出硬币,正面向上的概率是p,反面向上的概率是1 - p,当p不等于0.5时,这两个事件的概率就不一样了。怎么能凑出等概率呢?还是要利用概率的加法和乘法法则。这里用乘法,也就是连续的独立事件。
连续抛两次硬币,正反面的出现有四种情况,概率依次为:
这不,中间两种情况的概率是完全一样的。于是问题的解法就是连续抛两次硬币,如果两次得到的相同则重新抛两次;否则根据第一次(或第二次)的正面反面情况,就可以得到两个概率相等的事件。
设先抛先吃的概率为p1, 后抛先吃的概率为p2
那么有:
p1 = 1/2 + 1/2 * p2
p1 + p2 = 1
解方程可得,
p1 = 2/3
那么考虑这个方法:假设蛋一第一次扔在X层,第二次扔在比原来高 X-1层,... 高2, 高1,使得X+(X-1)+...+2+1=100,那么最坏情况总的次数就是:
如果在第X层就碎,那么蛋二最坏情况要扔X-1,所以总数是 1+X-1=X
如果在X+(X-1)碎,那么蛋二最坏情况要扔 X-2,所以2+X-2=X
...1+2+3+4+......+14>100
解得 X = 14.
⼆分查找排除楼层的速度⽆疑是最快的, 那⼲脆先⽤⼆分查找, 等到只剩 1 个鸡蛋的时候再执⾏线性扫描, 这样得到的结
果是不是就是最少的扔鸡蛋次数呢?
很遗憾, 并不是, ⽐如说把楼层变⾼⼀些, 100 层, 给你 2 个鸡蛋, 你在 50层扔⼀下, 碎了, 那就只能线性扫描 1〜49 层了, 最坏情况下要扔 50 次。
如果不要「⼆分」 , 变成「五分」 「⼗分」 都会⼤幅减少最坏情况下的尝试次数。 ⽐⽅说第⼀个鸡蛋每隔⼗层楼扔, 在哪⾥碎了第⼆个鸡蛋⼀个个线性扫描, 总共不会超过 20 次。
最优解其实是 14 次。
参考链接:https://www.jianshu.com/p/f9f5b66f8a32
1)首先我们最常想到的方法是读取文件a,建立哈希表(为什么要建立hash表?因为方便后面的查找),然后再读取文件b,遍历文件b中每个url,对于每个遍历,我们都执行查找hash表的操作,若hash表中搜索到了,则说明两文件共有,存入一个集合。
(2)但上述方法有一个明显问题,加载一个文件的数据需要50亿*64bytes = 320G远远大于4G内存,何况我们还需要分配哈希表数据结构所使用的空间,所以不可能一次性把文件中所有数据构建一个整体的hash表。所以虽然可行,但是无法满足需求。
(3)针对上述问题,我们分治算法的思想。
step1:遍历文件a,对每个url求取hash(url)%1000,然后根据所取得的值将url分别存储到1000个小文件(记为a0,a1,...,a999,每个小文件约300M),为什么是1000?主要根据内存大小和要分治的文件大小来计算,我们就大致可以把320G大小分为1000份,每份大约300M(当然,到底能不能分布尽量均匀,得看hash函数的设计)
step2:遍历文件b,采取和a相同的方式将url分别存储到1000个小文件(记为b0,b1,...,b999)(为什么要这样做? 文件a的hash映射和文件b的hash映射函数要保持一致,这样的话相同的url就会保存在对应的小文件中,比如,如果a中有一个url记录data1被hash到了a99文件中,那么如果b中也有相同url,则一定被hash到了b99中)
所以现在问题转换成了:找出1000对小文件中每一对相同的url(不对应的小文件不可能有相同的url)
step3:因为每个hash大约300M,所以我们再可以采用(1)中的想法
二叉树的最长路径的进阶版:https://blog.csdn.net/wangbaochu/article/details/53870330
- #include<iostream>
- #include<vector>
- #include<algorithm>
- int maxDistance = 0;
- std::vector<std::vector<int> > G(100001);//存储边信息
- inline void AddEdge(int v, int s)//把结点v和s关联
- {
- G[v].push_back(s);
- G[s].push_back(v);
- }
-
- int LastOrder(int pre, int cur)
- {
- int first = 0, second = 0;//最大值和次大值
- for (size_t i = 0; i < G[cur].size(); ++i)
- {
- if (G[cur][i] == pre)//一直向下,不着重复的边
- continue;
- int temp = LastOrder(cur, G[cur][i]);//向下找
- if (temp>first)
- {
- second = first;
- first = temp;
- }
- else if (temp > second)
- {
- second = temp;
- }
-
- }
- //注意:在以当前结点为根节点的子树中,最远两个结点的距离为first+second。
- maxDistance = std::max(maxDistance, first + second);
- return first + 1; //只返回当前子树的最大深度,父结点只需要知道子树的最大深度。
- }
-
- int main()
- {
- int N;
- std::cin >> N;
- int Ai, Bi;
- for (int i = 1; i < N; ++i)
- {
- std::cin >> Ai >> Bi;
- AddEdge(Ai, Bi);
- }
- LastOrder(0, 1);
- std::cout << maxDistance;
- return 0;
- }
- #使用循环进行拓扑排序
- def topoSort(G):
- #初始化计算被指向节点的字典
- cnt=dict((u,0) for u in G.keys())
- #若某节点被其他节点指向,该节点计算量+1
- for u in G:
- for v in G[u]:
- cnt[v]+=1
- #收集被指向数为0的节点,此时Q只有一个节点,即起始节点a
- Q=[u for u in cnt.keys() if cnt[u]==0]
- #记录结果
- seq=[]
- while Q:
- s=Q.pop()
- seq.append(s)
- for u in G[s]:
- cnt[u]-=1
- if cnt[u]==0:
- Q.append(u)
- return seq
-
- #有向无环图的邻接字典
- G={
- 'a':{'b','f'},
- 'b':{'c','d','f'},
- 'c':{'d'},
- 'd':{'e','f'},
- 'e':{'f'},
- 'f':{}
- }
这种属于二项分布的检验,会有2个数值方向。当概率p<0.626时,P(X<=70)>=0.9506(此时可以理解为概率过小,100次里不超过70次正面的可能性很大);当概率p>=0.775时,P(X>70)=1-0.0502=0.9498(此时可以理解为概率过大,100次里超过70次正面的可能性很大);所以当概率p在[0.626,0.775)区间内,在95%的置信区间(有95%把握)判断硬币出现正面的概率区间为[0.626,0.775)
可以得到对应的概率值,然后取计算Z值,可以得到95%置信区间对应的两边端点值
其中95置信区间下u一般为1.96
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。