LeetCode 981. 基于时间的键值存储 / 274. H 指数 / 275. H 指数 II
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 981. 基于时间的键值存储 / 274. H 指数 / 275. H 指数 II相关的知识,希望对你有一定的参考价值。
981. 基于时间的键值存储
2021.7.10 每日一题
题目描述
创建一个基于时间的键值存储类 TimeMap,它支持下面两个操作:
1. set(string key, string value, int timestamp)
存储键 key、值 value,以及给定的时间戳 timestamp。
2. get(string key, int timestamp)
返回先前调用 set(key, value, timestamp_prev) 所存储的值,其中 timestamp_prev <= timestamp。
如果有多个这样的值,则返回对应最大的 timestamp_prev 的那个值。
如果没有值,则返回空字符串("")。
示例 1:
输入:inputs = ["TimeMap","set","get","get","set","get","get"], inputs = [[],["foo","bar",1],["foo",1],["foo",3],["foo","bar2",4],["foo",4],["foo",5]]
输出:[null,null,"bar","bar",null,"bar2","bar2"]
解释:
TimeMap kv;
kv.set("foo", "bar", 1); // 存储键 "foo" 和值 "bar" 以及时间戳 timestamp = 1
kv.get("foo", 1); // 输出 "bar"
kv.get("foo", 3); // 输出 "bar" 因为在时间戳 3 和时间戳 2 处没有对应 "foo" 的值,所以唯一的值位于时间戳 1 处(即 "bar")
kv.set("foo", "bar2", 4);
kv.get("foo", 4); // 输出 "bar2"
kv.get("foo", 5); // 输出 "bar2"
示例 2:
输入:inputs = ["TimeMap","set","set","get","get","get","get","get"], inputs = [[],["love","high",10],["love","low",20],["love",5],["love",10],["love",15],["love",20],["love",25]]
输出:[null,null,null,"","high","high","low","low"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/time-based-key-value-store
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
还是前几天的哈希表,这次加了个二分查找,超过百分百
class TimeMap {
//所有 TimeMap.set 操作中的时间戳 timestamps 都是严格递增的。
//这句话有什么提示意义吗
//哈希表存储键,值是一个node,node有两个属性,一个time,一个值value
//node用一个list存储,因为set操作中时间戳是严格递增的
//所以二分查找取相应的值就可以了
class Node{
int time;
String value;
public Node(int t, String v){
time = t;
value = v;
}
}
Map<String, List<Node>> map;
/** Initialize your data structure here. */
public TimeMap() {
map = new HashMap<>();
}
public void set(String key, String value, int timestamp) {
List<Node> list = map.getOrDefault(key, new ArrayList<Node>());
list.add(new Node(timestamp, value));
map.put(key, list);
}
public String get(String key, int timestamp) {
if(!map.containsKey(key))
return "";
else{
List<Node> list = map.get(key);
int size = list.size();
int left = 0;
int right = size - 1;
while(left < right){
int mid = (right - left + 1) / 2 + left;
Node node = list.get(mid);
if(node.time <= timestamp){
left = mid;
}else{
right = mid - 1;
}
}
if(list.get(left).time > timestamp)
return "";
return list.get(left).value;
}
}
}
/**
* Your TimeMap object will be instantiated and called as such:
* TimeMap obj = new TimeMap();
* obj.set(key,value,timestamp);
* String param_2 = obj.get(key,timestamp);
*/
换种二分查找的形式
class TimeMap {
//所有 TimeMap.set 操作中的时间戳 timestamps 都是严格递增的。
//这句话有什么提示意义吗
//哈希表存储键,值是一个node,node有两个属性,一个time,一个值value
//node用一个list存储,因为set操作中时间戳是严格递增的
//所以二分查找取相应的值就可以了
class Node{
int time;
String value;
public Node(int t, String v){
time = t;
value = v;
}
}
Map<String, List<Node>> map;
/** Initialize your data structure here. */
public TimeMap() {
map = new HashMap<>();
}
public void set(String key, String value, int timestamp) {
List<Node> list = map.getOrDefault(key, new ArrayList<Node>());
list.add(new Node(timestamp, value));
map.put(key, list);
}
public String get(String key, int timestamp) {
if(!map.containsKey(key))
return "";
else{
List<Node> list = map.get(key);
int size = list.size();
int left = 0;
int right = size;
while(left < right){
int mid = (right - left) / 2 + left;
Node node = list.get(mid);
if(node.time <= timestamp){
left = mid + 1;
}else{
right = mid;
}
}
if(left - 1 < 0)
return "";
return list.get(left - 1).value;
}
}
}
/**
* Your TimeMap object will be instantiated and called as such:
* TimeMap obj = new TimeMap();
* obj.set(key,value,timestamp);
* String param_2 = obj.get(key,timestamp);
*/
274. H 指数
2021.7.11 每日一题
题目描述
给定一位研究者论文被引用次数的数组(被引用次数是非负整数)。编写一个方法,计算出研究者的 h 指数。
h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (N 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。且其余的 N - h 篇论文每篇被引用次数 不超过 h 次。
例如:某人的 h 指数是 20,这表示他已发表的论文中,每篇被引用了至少 20 次的论文总共有 20 篇。
示例:
输入:citations = [3,0,6,1,5]
输出:3
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/h-index
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
这题出的,总共有h篇论文引用至少h次,那么如果是[1,3,1],应该输出多少了
给的答案是1,那就意思是有1篇论文至少引用1次才对,其实意思是3篇论文至少引用了一次,引用次数大于等于1的论文数量要大于引用次数1,所以输出1。。所以输出的应该是次数,题目应该写成,至少h篇论文引用了h次。。。
算了,没啥可纠结的,计数完事了,其实很简单的一道题。题解里很多二分查找的,如果不让开新的空间可以用二分
看下一道题吧,这里理解的有点偏差
class Solution {
public int hIndex(int[] citations) {
int max = 0;
int l = citations.length;
for(int i = 0; i < l; i++){
max = Math.max(max, citations[i]);
}
int[] count = new int[max + 1];
for(int i = 0; i < l; i++){
count[citations[i]]++;
}
int res = 0;
//引用次数
for(int i = max; i >= 0; i--){
//检查引用次数等于i的文章数
res += count[i];
//如果有res篇文章引用数超过i
if(res >= i)
return i;
}
return 0;
}
}
275. H 指数 II
题目描述
给定一位研究者论文被引用次数的数组(被引用次数是非负整数),数组已经按照 升序排列 。
编写一个方法,计算出研究者的 h 指数。
h 指数的定义: “h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (N 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。(其余的 N - h 篇论文每篇被引用次数不多于 h 次。)"
示例:
输入: citations = [0,1,3,5,6]
输出: 3
解释: 给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 0, 1, 3, 5, 6 次。
由于研究者有 3 篇论文每篇至少被引用了 3 次,其余两篇论文每篇被引用不多于 3 次,所以她的 h 指数是 3。
说明:
如果 h 有多有种可能的值 ,h 指数是其中最大的那个。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/h-index-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
h是论文篇数…
这个题咋回事呢,一直想用left < right 写,结果搞了半天也搞不对,好烦,最后只能按官解改了个这样的二分,想想为什么
首先明确题意,到现在我还是不知道要输出的是文章数还是被引次数,例如[1,1,3],答案是1,那么按题中所给的意思就是1篇论文被引次数至少1次,其余2篇不多余1次。
[100]输出是1,意思是1篇论文引用次数至少1次。
加上括号里解释的那句话我现在才好像读懂题的意思了,意思就是说这两个部分可以用重叠,那么[1,1,3]就可以说通了
class Solution {
public int hIndex(int[] citations) {
//二分查找
int l = citations.length;
int left = 0;
int right = l - 1;
while(left <= right){
//mid没有具体含义,就是个下标
int mid = (right - left) / 2 + left;
//当前被引次数
int count = citations[mid];
//如果文章数大于引用次数,说明符合条件,试着增大被引次数
if(count < l - mid){
left = mid + 1;
//如果文章数小于引用次数,那么减少被引次数
}else{
right = mid - 1;
}
}
return l - left;
}
}
看了weiwei哥的二分查找,终于写出了一个符合我意思的二分。我习惯写这种二分就是跟着weiwei哥学的,不会了还得看weiwei哥啊,哈哈
这里首先要明确,mid不是指文章数,也不是指引用次数,它只是一个下标位置,可以理解为一个分割线,而我们要做的就是找到这个分割线最合适的位置。这个分割线得理解正确了才能写出二分的正确形式,再看题的意思,有h篇论文分别被引用至少h次。那么这个意思就是说论文篇数是小于等于引用次数的。分割线找的是,右边的最少引用次数大于等于右边的论文篇数
那么明白了一点,二分就好写了。先找分割线mid,如果分割线右边的最少引用次数也就是mid下标对应的值小于等于右边的论文篇数,说明是符合条件的,所以right = mid;反之,如果引用次数小于论文篇数,那么不符合条件,分割线靠左了,那么left = mid + 1
最后分割线是满足条件的最小位置,输出的是论文篇数,也就是l - left
自己写的时候理解不到位,反了
class Solution {
public int hIndex(int[] citations) {
//二分查找
int l = citations.length;
int left = 0;
int right = l - 1;
//特殊情况,如果最右边的位置是0,那么没有符合条件的,就输出0
if(citations[right] == 0)
return 0;
while(left < right){
//mid没有具体含义,就是个下标
int mid = (right - left) / 2 + left;
//当前被引次数
int count = citations[mid];
//如果文章数大于引用次数,说明分割线靠左了,试着增大分割线的位置
if(count < l - mid){
left = mid + 1;
//如果文章数小于等于引用次数,那么分割线靠右边了,尝试往左
}else{
right = mid;
}
}
return l - left;
}
}
那么到了这里再回过头来想昨天那个题为什么res > i,输出i,也就是引用次数就可以,而不是说输出res论文篇数呢。因为有这样一句话“(其余的 N - h 篇论文每篇被引用次数不多于 h 次)”,所以 i 是要小于等于res的,直接输出res的话,论文篇数可能包含了括号里面的论文,所以不准确。而输出 i 的话,是满足条件的最大的论文篇数
有点绕,建议直接理解这个二分,第一道H指数不用管了,没啥意义
以上是关于LeetCode 981. 基于时间的键值存储 / 274. H 指数 / 275. H 指数 II的主要内容,如果未能解决你的问题,请参考以下文章