933. 最近的请求次数
题干
写一个 RecentCounter 类来计算最近的请求。
它只有一个方法:ping(int t),其中 t 代表以毫秒为单位的某个时间。
返回从 3000 毫秒前到现在的 ping 数。
任何处于 [t - 3000, t] 时间范围之内的 ping 都将会被计算在内,包括当前(指 t 时刻)的 ping。
保证每次对 ping 的调用都使用比之前更大的 t 值。
示例:
输入:inputs = [“RecentCounter”,“ping”,“ping”,“ping”,“ping”], inputs = [[],[1],[100],[3001],[3002]]
输出:[null,1,2,3,3]
提示:
每个测试用例最多调用 10000 次 ping。
每个测试用例会使用严格递增的 t 值来调用 ping。
每次调用 ping 都有 1 <= t <= 10^9。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-recent-calls
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
代码
1. 两数之和
题干
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
思路1
显然此题可以用两个for循环暴力求解,但是时间复杂度过大,可以用线性复杂度的方法求解。
- 首先需要明确,用线性复杂度的方法就需要拿到一个数a,找到nums数组中是否存在数b,使得a+b=target。而数组存储对这种查找是极为不利的,查找的最快方法为哈希表。因此用map容器,数组的值为key,数组的索引为value。
- 第一遍哈希表,把数组元素全部放在map容器里。
- 第二遍搜索时,可以对数组从左往右依次扫描,扫描一个就到map容器里寻找是否存在target-a的数,如果存在,就返回数组的索引和map容器里对应元素的value。注意在操作的时候,需要排除同一个数使用两遍的情况,(不能用数a*2!=target判断)。
正确的判断方法:因为哈希表的存储是数组元素从左往右依次放进去进行存储的,所以哈希表中记录的value是最后一次数组元素出现的索引,比如数组[5,5,5],那么哈希表mp中,mp[5]=3.所以只要mp[target-num[i]] != i, 那么就不是同一个(位置上的)数用两遍。
代码1
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> a;//建立hash表存放数组元素
vector<int> b(2,-1);//存放结果
for(int i=0;i<nums.size();i++)
a.insert(map<int,int>::value_type(nums[i],i));
for(int i=0;i<nums.size();i++)
{
if(a.count(target-nums[i])>0&&(a[target-nums[i]]!=i))
//判断是否找到目标元素且目标元素不能是本身
{
b[0]=i;
b[1]=a[target-nums[i]];
break;
}
}
return b;
};
};
思路2
当然思路1是两遍哈希表,事实上1遍哈希表也可以,在放入map容器之前就检查之前的map容器中有没有与之互补的元素,如果有,函数直接结束,如果没有,就把它放入哈希表中。
代码2
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> a;//提供一对一的hash
vector<int> b(2,-1);//用来承载结果,初始化一个大小为2,值为-1的容器b
for(int i=0;i<nums.size();i++)
{
if(a.count(target-nums[i])>0)
{
b[0]=a[target-nums[i]];
b[1]=i;
break;
}
a[nums[i]]=i;//反过来放入map中,用来获取结果下标
}
return b;
};
};
2. 两数相加
题干
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
思路
这是简单的两个链表遍历的题目,只需要创建一个新的链表,然后利用一个int变量作为进位标记,模拟加法过程,每位存入链表中即可
实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int count = 0;
ListNode *tmpl1 = new ListNode;
tmpl1 = l1;
ListNode *tmpl2 = new ListNode;
tmpl2 = l2;
ListNode *tmpr = new ListNode;
ListNode *tmphead = new ListNode;
tmphead = tmpr;
// ListNode *a =
while(tmpl1 != NULL && tmpl2 !=NULL)
{
tmpr->next = new ListNode((tmpl1->val + tmpl2->val + count)%10);
tmpr = tmpr->next;
count = (tmpl1->val + tmpl2->val + count)/10;
tmpl1 = tmpl1->next;
tmpl2 = tmpl2->next;
}
while(tmpl1 != NULL)
{
ListNode *tmp = new ListNode;
tmp->val = (tmpl1->val + count)%10;
count = (tmpl1->val+ count)/10;
tmp->next = NULL;
tmpr->next = tmp;
tmpr = tmpr->next;
tmpl1 = tmpl1->next;
}
while(tmpl2 != NULL)
{
ListNode *tmp = new ListNode;
tmp->val = (tmpl2->val + count)%10;
count = (tmpl2->val+ count)/10;
tmp->next = NULL;
tmpr->next = tmp;
tmpr = tmpr->next;
tmpl2 = tmpl2->next;
}
if(count == 1)
{
ListNode *tmp = new ListNode;
tmp->val = 1;
tmp->next = NULL;
tmpr->next = tmp;
}
tmphead = tmphead->next;
return tmphead;
}
};
3. 无重复字符的最长子串
题干
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
思路
这种连续的子串,一般都是使用“滑动窗口”解决,只需要线性时间的复杂度。
- 因为输入是string类型,且在搜索的过程中只需要检查字符是否存在,而不需要知道字符的具体位置,所以用unordered_set < char > a存储滑动窗口即可。(unordered_set < char > a比 set < char > a更快,两者的区别:https://blog.csdn.net/haluoluo211/article/details/82468061,unordered_set 是哈希表, set 是红黑树)
- 设置一个末尾指针stre,用来标记窗口的末尾,i标记窗口的开头。末尾指向的那个字符在unordered_set 容器中没有出现,窗口右指针向右移动一格,并将其纳入容器中。一旦末尾指向的那个字符在unordered_set 容器中出现,计算当前容器字符个数。
接着,窗口左指针向左移动一格,继续检查容器中是否还出现重复的字符,直到没有重复的字符,左指针停止移动,右指针开始移动。 - 当右指针移动到末尾时,跳出for循环。
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set< char > a;
int stre, ans, i;
ans = 0;
stre = -1;
for(i=0; i<s.length(); i++)
{
if(i != 0)
{
a.erase(s[i-1]);
}
while(stre+1<s.length() && a.count(s[stre+1]) == 0)
{
a.insert(s[stre+1]);
stre++;
}
ans = max(ans, stre-i+1);
if(stre == s.length()-1)
break;
}
return ans;
}
};