刷题记录-哈希表

560. 和为K的子数组

难度中等478
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :

  1. 数组的长度为 [1, 20,000]。
  2. 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
    Code:
class Solution {
public:
    //前缀和 + 哈希表优化
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int,int> mp;
        mp[0]=1;
        //pre[i] 为 [0..i] 里所有数的和
        int pre=0;
        int cnt=0;
        for(int i=0;i<nums.size();++i){
            //pre[i]−pre[j−1]==k
            //pre[j−1]==pre[i]−k
            pre+=nums[i];
            if(mp.find(pre-k)!=mp.end()) cnt+=mp[pre-k];
            mp[pre]++;
        }
        return cnt;
    }
};

超时:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int,int> mp;
        for(int i=0;i<nums.size();++i){
            int sum=0;
            for(int j=i;j<nums.size();++j){
                //int tmp=calSum(nums,i,j);
                sum+=nums[j];//在计算[i,j]时可以利用[i,j-1]的值
                mp[sum]++;
            }
        }
        for(auto m:mp){
            if(m.first==k) return m.second;
        }
        return 0;
    }
};

166. 分数到小数

难度中等140
给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。
如果小数部分为循环小数,则将循环的部分括在括号内。
示例 1:
输入: numerator = 1, denominator = 2
输出: “0.5”
示例 2:
输入: numerator = 2, denominator = 1
输出: “2”
示例 3:
输入: numerator = 2, denominator = 3
输出: “0.(6)”
Awsl:

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator) {
        if(numerator==0) return "0";
        if(denominator==0) return "";
        string res="";
        long long num=static_cast<long long>(numerator);//转换为longlong防止溢出
        long long denom=static_cast<long long>(denominator);
        if((num>0)^(denom>0)) res.push_back('-');//处理正负号,一正一负取负号
        //要考虑负分数以及极端情况
        //分子分母全部转换为正数
        num=llabs(num);
        denom=llabs(denom);
        res.append(to_string(num/denom));//处理整数部分
        num%=denom;//处理小数部分//获得余数
        if(num==0) return res; //余数为0,表示整除了,直接返回结果
        res.push_back('.');//余数不为0,添加小数点
        int ind=res.size()-1;//获得小数点的下标
        unordered_map<int,int> map; //map用来记录出现重复数的下标,然后将'('插入到重复数前面就好了
        while(num&&map.count(num)==0){//小数部分:余数不为0且余数还没有出现重复数字
            map[num]=++ind;
            num*=10;//余数扩大10倍,然后求商,和草稿本上运算方法是一样的
            res+=to_string(num/denom);
            num%=denom;
        }
        if(map.count(num)==1){ //出现循环余数,直接在重复数字前面添加'(',字符串末尾添加')'
            res.insert(map[num],"(");
            res.push_back(')');
        }
        return res;

    }
};

454. 四数相加 II

难度中等162
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
例如:
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:

  1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
  2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
    修改(四数相加简化成两数相加):
class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int,int> hash1;
        unordered_map<int,int> hash2;
        for(int i=0;i<A.size();++i){
            for(int j=0;j<B.size();++j){
                int tmpSum=A[i]+B[j];
                hash1[tmpSum]++;
            }
        }
        for(int i=0;i<C.size();++i){
            for(int j=0;j<D.size();++j){

                int tmp=C[i]+D[j];
                hash2[tmp]++;
            }
        }
        int cnt=0;
        for(auto hash:hash1){
            int tmp=-hash.first;
            if(hash2.find(tmp)!=hash2.end()){
                cnt+=hash2[tmp]*hash.second;
            }
        }
        return cnt;

    }
};

380. 常数时间插入、删除和获取随机元素

难度中等142
设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构。

  1. insert(val):当元素 val 不存在时,向集合中插入该项。
  2. remove(val):元素 val 存在时,从集合中移除该项。
  3. getRandom:随机返回现有集合中的一项。每个元素应该有相同的概率被返回。
    示例 :
    // 初始化一个空的集合。
    RandomizedSet randomSet = new RandomizedSet();
    // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
    randomSet.insert(1);
    // 返回 false ,表示集合中不存在 2 。
    randomSet.remove(2);
    // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
    randomSet.insert(2);
    // getRandom 应随机返回 1 或 2 。
    randomSet.getRandom();
    // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
    randomSet.remove(1);
    // 2 已在集合中,所以返回 false 。
    randomSet.insert(2);
    // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
    randomSet.getRandom();
    参考:
class RandomizedSet {
    /*此题的正确解法是利用到了一个一维数组和一个 HashMap,
    其中数组用来保存数字,HashMap 用来建立每个数字和其在数组中的位置之间的映射。
    插入操作——先看这个数字是否已经在 HashMap 中存在,
    如果存在的话直接返回 false,不存在的话,将其插入到数组的末尾,
    然后建立数字和其位置的映射(map的第一个参数是元素的值,第二个参数是该值在数组中的下标)
    
    删除操作——比较 tricky 的,还是要先判断其是否在 HashMap 里,如果没有,直接返回 false。
    由于 HashMap 的删除是常数时间的,而数组并不是,
    为了使数组删除也能常数级,实际上将要删除的数字和数组的最后一个数字调换个位置,
    然后修改对应的 HashMap 中的值,这样只需要删除数组的最后一个元素即可,保证了常数时间内的删除
    
    返回随机数——对于数组来说就很简单了,只要随机生成一个位置,返回该位置上的数字即可
*/
    unordered_map<int,int> hash;
    vector<int> res;
public:
    /** Initialize your data structure here. */
    RandomizedSet() {

    }
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    bool insert(int val) {
        if(hash.find(val)==hash.end()){
            res.push_back(val);
            hash[val]=res.size()-1;
            return true;
        }else{
            return false;
        }
    }    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    bool remove(int val) {
        if(hash.find(val)!=hash.end()) {
            hash[res.back()] = hash[val];//!!!!!!!!
            int index=hash[val];
            swap(res[index],res.back());
            res.pop_back();
            hash.erase(val);
            
            return true;
        }
        return false;
    }
    /** Get a random element from the set. */
    int getRandom() {
        return res[rand() % res.size()];     
    }
};
/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet* obj = new RandomizedSet();
 * bool param_1 = obj->insert(val);
 * bool param_2 = obj->remove(val);
 * int param_3 = obj->getRandom();
 */

347. 前 K 个高频元素

难度中等368
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
• 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
• 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
• 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
• 你可以按任意顺序返回答案。
修改:键->数字,值->出现次数(也可以反过来)

class Solution {
public:
    static bool cmp(const pair<int,int> &a,const pair<int,int> &b){
        return a.second>b.second;//注意排序方向
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        vector<int> res;
        unordered_map<int,int> mp;        
        for(int num:nums){
            mp[num]++;
        }        
        vector<pair<int,int>> tmp(mp.begin(),mp.end());
        sort(tmp.begin(),tmp.end(),cmp);
        for(auto m:tmp){
            res.push_back(m.first);
            k--;
            if(k<=0) break;
        }
        return res;
    }
};
class Solution {
public:
    static bool cmp(const pair<int,int> &a,const pair<int,int> &b){
        return a.second>b.second;//注意排序方向
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        vector<int> res;
        unordered_map<int,int> mp;        
        for(int num:nums){
            mp[num]++;
        }        
        vector<pair<int,int>> tmp;
        for(auto m:mp) tmp.push_back(make_pair(m.second,m.first));
        sort(tmp.begin(),tmp.end());
        int i=0;
        while(i<k){
            res.push_back(tmp[tmp.size()-i-1].second);
            //cout<<tmp[tmp.size()-i-1].second<<endl;
            i++;
        }
        return res;
    }
};

138. 复制带随机指针的链表

难度中等301
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
• val:一个表示 Node.val 的整数。
• random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:
• -10000 <= Node.val <= 10000
• Node.random 为空(null)或指
修正:

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {   
        if(head==NULL)      return NULL;
        Node* cur=head;
        while(cur){
            Node* tmp=new Node(cur->val);
            tmp->next=cur->next;
            cur->next=tmp;     
            cur=tmp->next;       
        }
        cur=head;
        while(cur){
            Node* tmp=cur->next;
            if(cur->random) tmp->random=cur->random->next;//cur!!!
            cur=tmp->next;
        }
        cur=head;
        Node* p=head->next;
        while(cur){
            Node* tmp=cur->next;
            cur->next=tmp->next;
            if(tmp->next) tmp->next=tmp->next->next;
            cur=cur->next;
        }
        return p;
        
    }
};

49. 字母异位词分组

难度中等372
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出:
[
[“ate”,“eat”,“tea”],
[“nat”,“tan”],
[“bat”]
]
说明:
• 所有输入均为小写字母。
• 不考虑答案输出的顺序
Code:

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {  
        //只要引入一个hash表,索引是排序后的单词,值为结果vector的下标,循环一遍就好了
        vector<vector<string>> res;      
        //if(strs.size()==0) return res;
        unordered_map<string,int> mp;
        int sub=0;//res的下标
        for(int i=0;i<strs.size();i++){
            string tmp=strs[i];
            sort(tmp.begin(),tmp.end());
            if(mp.find(tmp)!=mp.end()){
                res[mp[tmp]].push_back(strs[i]);
            }else{
                vector<string> v(1,strs[i]);
                res.push_back(v);
                mp[tmp]=sub++;
            }
        }
        return res;
    }
};

超时!:

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {        
        //if(strs.size()==0) return res;
        unordered_map<string,int> mp;
        for(int i=0;i<strs.size();++i){
            string tmp=strs[i];
            sort(tmp.begin(),tmp.end());
            mp[tmp]++;
        }
        int len=mp.size();
        vector<vector<string>> res;
        for(auto m:mp){
            vector<string> out;
            for(int j=0;j<strs.size();++j){
                string tmp=strs[j];
                sort(tmp.begin(),tmp.end());
                if(tmp==m.first&&m.second>=0){
                    out.push_back(strs[j]);
                    m.second--;
                }
            }
            res.push_back(out);
        }
        return res;
        
    }
};

36. 有效的数独

难度中等351
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true
示例 2:
输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
说明:
• 一个有效的数独(部分已被填充)不一定是可解的。
• 只需要根据以上规则,验证已经填入的数字是否有效即可。
• 给定数独序列只包含数字 1-9 和字符 ‘.’ 。
• 给定数独永远是 9x9 形式的。
My:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int row=board.size();
        int col=board[0].size();
        for(int i=0;i<9;++i){
            unordered_map<char,int> mp;
            for(int j=0;j<9;++j){
                //if(board[i][j]=='.') continue;
                mp[board[i][j]]++;
                //cout<<'r'<<endl;
                if(mp[board[i][j]]>1&&board[i][j]!='.') return false;
            }
        }
        for(int i=0;i<9;++i){
            unordered_map<char,int> mp;
            for(int j=0;j<9;++j){
                mp[board[j][i]]++;
                //cout<<'c'<<endl;
                if(mp[board[j][i]]>1&&board[j][i]!='.') return false;
            }
        }
        for(int i=0;i<9;i+=3){            
            for(int j=0;j<9;j+=3){
                cout<<i<<'*'<<j<<endl<<endl;
                unordered_map<char,int> mp;
                for(int m=i;m<i+3;m++){
                    for(int n=j;n<j+3;n++){
                        cout<<m<<'*'<<n<<endl;
                        if(board[m][n]=='.') continue;
                        mp[board[m][n]]++;
                        if(mp[board[m][n]]>1&&board[m][n]!='.') return false;                       
                    }
                }
                

            }
        }

        return true;
        
    }
};

3. 无重复字符的最长子串(剑指48)

难度中等3855
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> hash;
        int res = 0;
        //原字符串的一个滑动窗口,并维护窗口内不能有重复字符,同时更新窗口的最大值。
        for (int i = 0, j = 0; i < s.size(); i ++){
            hash[s[i]] ++;          
            //第一次出现次数大于1时,将s[i]的次数减到1,j从0开始向右移动,直到使其为1;
            while (hash[s[i]] > 1)  {
                hash[s[j ++]] --;   
            }
            res = max(res, i - j + 1);
        }
        return res;        
    }
};

387. 字符串中的第一个唯一字符

难度简单220
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
示例:
s = “leetcode”
返回 0
s = “loveleetcode”
返回 2
提示:你可以假定该字符串只包含小写字母。
My:

class Solution {
public:
    int firstUniqChar(string s) {
        if(s.empty()) return -1;
        unordered_map<char,int> mp;
        for(char c:s){
            mp[c]++;
        }
        int res=-1;
        for(int i=0;i<s.size();++i){
            if(mp[s[i]]==1){
                res=i;
                break;
            }
        }
        return res;

    }
};

350. 两个数组的交集 II

难度简单291
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
说明:
• 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
• 我们可以不考虑输出结果的顺序。
进阶:
• 如果给定的数组已经排好序呢?你将如何优化你的算法?
• 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
• 如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        /*使用 set 来实现线性时间复杂度。需要使用 HashMap 来跟踪每个数字出现的次数。
        先在 HashMap 记录一个数组中的存在的数字和对应出现的次数。
        然后,遍历第二个数组,检查数字在 HashMap 中是否存在,
        如果存在且计数为正,则将该数字添加到答案并减少 HashMap 中的计数 */
        if (nums1.size() > nums2.size()) {
            return intersect(nums2, nums1);
        }
        vector<int> res;
        unordered_map<int,int> mp;
        for(int num1:nums1){
           mp[num1]++;                
        }
        for(int num2:nums2){
            if(mp.find(num2)!=mp.end()&&mp[num2]>0){                
                    res.push_back(num2);
                    mp[num2]--;
            }
        }
        return res;
    }
};

面试题 02.01. 移除重复节点

难度简单33
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
示例2:
输入:[1, 1, 1, 1, 2]
输出:[1, 2]
提示:

  1. 链表长度在[0, 20000]范围内。
  2. 链表元素在[0, 20000]范围内。
    进阶:
    如果不得使用临时缓冲区,该怎么解决?
    参考题解:https://leetcode-cn.com/problems/remove-duplicate-node-lcci/solution/yi-chu-zhong-fu-jie-dian-by-leetcode-solution/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
//哈希表:
class Solution {
public:
    ListNode* removeDuplicateNodes(ListNode* head) {
        unordered_set<int> mp;
        if(head==NULL||head->next==NULL) return head;
        ListNode* p=head;
        mp.insert(p->val);
        while(p->next){
            //ListNode* tmp=p->next;
            bool is=mp.count(p->next->val);
            if(is){
                p->next=p->next->next;                
            }else{
                mp.insert(p->next->val);
                p=p->next;
            }            
        }
        p->next=NULL;
        return head;
    }
};

//双层链表循环:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeDuplicateNodes(ListNode* head) {
        if(head==NULL||head->next==NULL) return head;
        ListNode* p=head;
        while(p){
            ListNode* tmp=p;
            while(tmp->next){
                if(p->val==tmp->next->val){
                    tmp->next=tmp->next->next;
                }else{
                    tmp=tmp->next;
                }
            }
            p=p->next;
        }

        return head;
    }
};

242. 有效的字母异位词

难度简单206
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
说明:
你可以假设字符串只包含小写字母。
进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
My1:

class Solution {
public:
    bool isAnagram(string s, string t) {
        sort(s.begin(),s.end());
        sort(t.begin(),t.end());
        if(s==t) return true;
        return false;
    }
};

My2:

class Solution {
public:
    bool isAnagram(string s, string t) {
        unordered_map<char,int> mp;
        for(char c:s){
            mp[c]++;
        }
        for(char c:t){
            mp[c]--;
        } 
        for(auto m:mp){
            if(m.second!=0) return false;
        }
        return true;
    }
};

217. 存在重复元素

难度简单260
给定一个整数数组,判断是否存在重复元素。
如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
My:

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_set<int> mp;
        for(int num:nums){
            if(mp.find(num)!=mp.end()) return true;
            else mp.insert(num);
        }
        return false;
    }
};

204. 计数质数

难度简单368
统计所有小于非负整数 n 的质数的数量。
示例:
输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
Not my:

class Solution {
public:
    bool isPrime(int n){
        for(int i=2;i*i<n;++i){//!!!!!!
            if(n%i==0) return false;
        }
        return true;
    }
    int countPrimes(int n) {
        if(n<=1) return 0;
        if(n==3) return 1;
        vector<bool> v(n,true);
        for(int i=2;i*i<n;i++){//!!!
            if(isPrime(i)){
                for(int j=i*i;j<n;j+=i){//!!
                    v[j]=false;
                }
            }
        }
        int cnt=0;
        for(int i=2;i<n;i++){
            if(v[i]) cnt++;
        }
        return cnt;
    }
};

202. 快乐数

难度简单375
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
My1:

class Solution {
public:
    int calHapppy(int n){
        int res=0;
        while(n){
            res+=pow(n%10,2);
            n=n/10;
        }
        return res;
    }
    bool isHappy(int n) {
        set<int> mp;
        while(n!=1){
            int tmp=calHapppy(n);
            mp.insert(n);
            if(mp.find(tmp)!=mp.end()) return false;
            if(tmp==1) return true;
            n=tmp;
        }
        return true;
    }
};

My2:

class Solution {
public:
    int calHapppy(int n){
        int res=0;
        while(n){
            res+=pow(n%10,2);
            n=n/10;
        }
        return res;
    }
    bool isHappy(int n) {
        unordered_map<int,int> mp;
        while(true){
            int tmp=calHapppy(n);
            mp[n]++;;
            if(mp[tmp]>1) return false;
            if(tmp==1) return true;
            n=tmp;
        }
        return true;
    }
};

136. 只出现一次的数字

难度简单1341
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
My1:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int,int> mp;
        for(int num:nums){
            mp[num]++;
        }
        for(int num:nums){
            if(mp[num]==1) return num;
        }
        return -1;

    }
};

My2:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        if(nums.empty()) return -1;
        //int res=nums[0];
        for(int i=1;i<nums.size();++i){
            nums[0]^=nums[i];
            //res^=nums[i];
        }
        return nums[0];

    }
};

1. 两数之和

难度简单8497
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mp;
        for(int i=0;i<nums.size();++i){
            mp[nums[i]]=i;
        }
        for(int i=0;i<nums.size();++i){
            int num=nums[i];
            int t=target-num;
            if(mp.count(t)>=1&&mp[t]!=i){
                return vector<int>{i,mp[t]};
            }
        }
        return vector<int>();        
    }
};

剑指Offer(五十六):数组中唯一只出现一次的数字(重要,哈希表,位运算)

剑指 Offer 56 - II. 数组中数字出现的次数 II
难度中等38
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1

限制:
• 1 <= nums.length <= 10000
• 1 <= nums[i] < 2^31
1.) 碰到次数,首先想到用哈希表。时间复杂度:O(n),空间复杂度O(n)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res;
        unordered_map<int,int> mp;
        for(int num:nums){
            mp[num]++;
        }
        for(int num:nums){
            if(mp[num]==1) return num;
        }
        return res;

    }
};

2.) 排序数组中寻找只出现一次,时间复杂度:O(nlogn),空间复杂度O(1)
3.) hash_set, 将输入数组存储到 HashSet,然后使用 HashSet 中数字和的三倍与数组之和比较。时间复杂度:O(n),空间复杂度O(n)
3×(a+b+c)−(a+a+a+b+b+b+c)=2c

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        long sum_set = 0;
        long sum_array = 0;
        unordered_set<long> s;
        for (int n : nums){
            sum_array+=n;
            s.insert((long)n);
        }
        for (auto num : s){
            sum_set+=num;
        }
        res =(3 * sum_set - sum_array)/2;
        return res;
    }
};
4.) 

位运算,
• 记录每一位不为0的数字出现的次数
• 如果出现的次数对3取模为1,则说明只出现一次的数字此位也是1
• 将所有模3为1的位想加,得到最终结果
时间复杂度:O(n),空间复杂度:O(1)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        for (int i = 0; i < 32; i++){
            int count = 0;
            for (auto n : nums){
                if ((1 << i ) & n) 
                    count++;
            }
            if (count % 3) 
                ans += (1 << i);
        }
        return ans;
    }
};

剑指Offer(五十):第一个只出现一次的字符 (重要,哈希表)

剑指 Offer 50. 第一个只出现一次的字符
难度简单29
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例:
s = “abaccdeff”
返回 “b”
s = “”
返回 " "
限制:
0 <= s 的长度 <= 50000

哈希表,C++利用unordered_map<int,int>来进行次数统计,可以用int类型是因为c++会自动将字符转成对应的ASCII码数字,可以利用unordered_map<char,int>来进行次数统计.Python 利用collections.Counter()模块进行次数统计。
时间复杂度为O(n),空间复杂度O(n)。

class Solution {
public:
    char firstUniqChar(string s) {
        char res=' ';
        unordered_map<char,int> mp;
        if(s.size()==0) return res;
        for(int i=0;i<s.size();++i){
            mp[s[i]]++;            
        }
        for(int i=0;i<s.size();++i){
            if(mp[s[i]]==1) return s[i];
        }
        return res;

    }
};

剑指 Offer 48. 最长不含重复字符的子字符串

难度中等52
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
提示:
• s.length <= 40000

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> hash;
        int res = 0;
        //原字符串的一个滑动窗口,并维护窗口内不能有重复字符,同时更新窗口的最大值。
        for (int i = 0, j = 0; i < s.size(); i ++){
            hash[s[i]] ++;          
            //第一次出现次数大于1时,将s[i]的次数减到1,j从0开始向右移动,直到使其为1;
            while (hash[s[i]] > 1)  {
                hash[s[j ++]] --;   
            }
            res = max(res, i - j + 1);
        }
        return res;
    }
};
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值