leetcode题解

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循环暴力求解,但是时间复杂度过大,可以用线性复杂度的方法求解。

  1. 首先需要明确,用线性复杂度的方法就需要拿到一个数a,找到nums数组中是否存在数b,使得a+b=target。而数组存储对这种查找是极为不利的,查找的最快方法为哈希表。因此用map容器,数组的值为key,数组的索引为value。
  2. 第一遍哈希表,把数组元素全部放在map容器里。
  3. 第二遍搜索时,可以对数组从左往右依次扫描,扫描一个就到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” 是一个子序列,不是子串。

思路

这种连续的子串,一般都是使用“滑动窗口”解决,只需要线性时间的复杂度。

  1. 因为输入是string类型,且在搜索的过程中只需要检查字符是否存在,而不需要知道字符的具体位置,所以用unordered_set < char > a存储滑动窗口即可。(unordered_set < char > a比 set < char > a更快,两者的区别:https://blog.csdn.net/haluoluo211/article/details/82468061,unordered_set 是哈希表, set 是红黑树)
  2. 设置一个末尾指针stre,用来标记窗口的末尾,i标记窗口的开头。末尾指向的那个字符在unordered_set 容器中没有出现,窗口右指针向右移动一格,并将其纳入容器中。一旦末尾指向的那个字符在unordered_set 容器中出现,计算当前容器字符个数。
    接着,窗口左指针向左移动一格,继续检查容器中是否还出现重复的字符,直到没有重复的字符,左指针停止移动,右指针开始移动。
  3. 当右指针移动到末尾时,跳出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;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值