文章目录
1.LeetCode:981. 基于时间的键值存储
设计一个基于时间的键值数据结构,该结构可以在不同时间戳存储对应同一个键的多个值,并针对特定时间戳检索键对应的值。
实现 TimeMap 类:
TimeMap() 初始化数据结构对象
void set(String key,
String value, int timestamp) 存储键 key、值 value,以及给定的时间戳 timestamp。
String get(String key, int timestamp)
返回先前调用 set(key, value, timestamp_prev) 所存储的值,其中 timestamp_prev <= timestamp 。
如果有多个这样的值,则返回对应最大的 timestamp_prev 的那个值。
如果没有值,则返回空字符串(“”)。
示例:
输入:
[“TimeMap”, “set”, “get”, “get”, “set”, “get”, “get”]
[[], [“foo”, “bar”, 1], [“foo”, 1], [“foo”, 3], [“foo”, “bar2”, 4], [“foo”, 4], [“foo”, 5]]
输出:
[null, null, “bar”, “bar”, null, “bar2”, “bar2”]
提示:
1 <= key.length, value.length <= 100
key 和 value 由小写英文字母和数字组成
1 <= timestamp <= 1e7
set 操作中的时间戳 timestamp 都是严格递增的
最多调用 set 和 get 操作 2 * 1e5 次
这道题可以在map里面套个map,第一个map的key为题目key,第二个map的key为时间戳,值为val,这样我们对于get操作就只需要利用map中的lower_bound来找到time+1,在让他自减即可。
class TimeMap {
unordered_map<string,map<int,string>> map;
public:
TimeMap() {
map.clear();
}
void set(string key, string value, int timestamp) {
map[key][timestamp]=value;
}
string get(string key, int timestamp) {
auto tmp=map[key].lower_bound(timestamp+1);
//因为要找到小于等于timestamp的最大key,这里可以找timesta+1然后让他自减
if(tmp==map[key].begin()){
return "";
}//找不到就返回空
tmp--;
return tmp->second;
}
};
2.LeetCode:400. 第 N 位数字
给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …] 中找出并返回第 n 位上的数字。
输入:n = 3
输出:3
提示:
1 <= n <= 2^31 - 1
首先明确n的意义,他指的是将1-n的所有数字拼接成一个字符串后,数字的位数。一个比较简单且效率高的做法是模拟.
1-9,10范围内的数字有九个,位数是9.
10-99,100范围内的数字有90个,位数是90 * 2
100-999,1000范围内的数字有900个,位数是900 * 3
找到了这个规律之后,我们要做的就是先确定n的范围,然后找到具体的数字,之后再确定具体的位数即可
class Solution {
#define ll long long
public:
int findNthDigit(int n) {
int cnt=1;//某个范围开始的数字
int ncnt=1;//某范围的位数
while(n>9*(ll)cnt*ncnt){
n-=9*cnt*ncnt;
cnt*=10;
++ncnt;
}
int count=(n-1)/ncnt;
//n-1是为了防止位数和n相等的情况,比如n =3,ncnt=3,这样count=1而不是0
cnt+=count;
n-=count*ncnt;
n=ncnt-n;
while(n){
cnt/=10;
n--;
}//拿到倒数第n位的数字返回即可
return cnt%10;
}
};
3.LeetCode:1300. 转变数组后最接近目标值的数组和
给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。
如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。
请注意,答案不一定是 arr 中的数字。
示例 1:
输入:arr = [4,9,3], target = 10
输出:3
示例 2:
输入:arr = [2,3,5], target = 10
输出:5
示例 3:
输入:arr = [60864,25176,27249,21296,20204], target = 56803
输出:11361
提示:
1 <= arr.length <= 10^4
1 <= arr[i], target <= 10^5
先对arr排序,由于题目要求找到某个数,使得让数组中大于他的全部变为他后数组和与target最接近。
那么我们就以数组中的每个数字为依据。每次检测如果以当前数字为标准,数组的和是否大于target,如果大于了就说明不能再往下继续选择需要求出答案。
我们想做的是找出一个最接近的数字,那么很自然的想到平均值。比如arr[0]*n就已经大于了target了,那么数组剩下的数字就没有检查的必要了。接下来我们去检查target/n这个数字,如果能够除尽正好是我们想要的结果,但如果没有除尽,就代表着他有余数,我们这时候去看吧剩下未检查的数字都变为target/n和(target/n)+1这两个哪个距离target最接近,找出来并且返回他即可。
具体的操作就是我们先把已经检查过的数字的和存起来,然后不断遍历数组直到arr[i] * (n-i)大于等于target-prev,之后对i进行判断即可。
class Solution {
public:
int findBestValue(vector<int>& arr, int target) {
sort(arr.begin(),arr.end());
int sum=0;
for(auto i:arr){
sum+=i;
}
int n=arr.size();
if(sum<=target){
return arr.back();
}
if(arr[0]*n>=target){
int ans=target/n;
if(target-ans*n<=(ans+1)*n-target){
return ans;
}else return ans+1;
}
int prev=arr[0];
for(int i=1;i<n;++i){
int nsum=prev+arr[i]*(n-i);
if(nsum>=target){
int ans=(target-prev)/(n-i);
if(target-prev-ans*(n-i)<=(ans+1)*(n-i)-target+prev){
return ans;
}else
return ans+1;
}
prev+=arr[i];
}
return 0;
}
};
4.LeetCode:1713. 得到子序列的最少操作次数
给你一个数组 target ,包含若干 互不相同 的整数,以及另一个整数数组 arr ,arr 可能 包含重复元素。
每一次操作中,你可以在 arr 的任意位置插入任一整数。比方说,如果 arr = [1,4,1,2] ,那么你可以在中间添加 3 得到 [1,4,3,1,2] 。你可以在数组最开始或最后面添加整数。
请你返回 最少 操作次数,使得 target 成为 arr 的一个子序列。
一个数组的 子序列 指的是删除原数组的某些元素(可能一个元素都不删除),同时不改变其余元素的相对顺序得到的数组。比方说,[2,7,4] 是 [4,2,3,7,2,1,4] 的子序列(加粗元素),但 [2,4,2] 不是子序列。
示例 1:
输入:target = [5,1,3], arr = [9,4,2,3,4]
输出:2
示例 2:
输入:target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1]
输出:3
提示:
1 <= target.length, arr.length <= 1e5
1 <= target[i], arr[i] <= 1e9
target 不包含任何重复元素。
这道题目还是比较简单的,一旦找到了思路就很容易突破了。先在arr中找到target的元素,并且每找到一个就存下他们在target的下标,之后利用找到这些下标的最长递增序列。这样就代表着我们在arr中找到了target除去了某些数字的最长子序列(可能并不连续)。
那么要在arr中找到一个可以不连续的子数组使得他们为target,就只需要在对应位置增添上剩余的数字即可,这一定是次数最小的方法。
class Solution {
unordered_map<int,int> pos;
vector<int> lcs;
public:
int minOperations(vector<int>& target, vector<int>& arr) {
for(int i=0;i<target.size();++i){
pos[target[i]]=i;
}
for(int i=0;i<arr.size();++i){
if(pos.find(arr[i])!=pos.end()){
lcs.push_back(pos[arr[i]]);
cout<<lcs.back()<<" ";
}
}
int a[100005],asize=0;
for(int i=0;i<lcs.size();++i){
int l=1,r=asize;
int ans=-1;
while(l<=r){
int mid=l+((r-l)>>1);
if(lcs[i]<=a[mid]){
r=mid-1;
ans=mid;
}else l=mid+1;
}
if(ans==-1){
a[++asize]=lcs[i];
}else a[ans]=lcs[i];
}
return target.size()-asize;
}
};