LeetCode题解-03(栈、队列、双指针、哈希表)


目录
  • LeetCode题解
    • chap-7: 栈、队列
        • 1、最小栈【设计】
        • 2、比较含退格的字符串
        • 3、设计一个支持增量操作的栈 【×】
        • 4、设计循环队列
        • 5、设计循环双端队列
        • 6、验证栈序列
        • 7、删除字符串中的所有相邻重复项
        • 8、删除字符串中的所有相邻重复项 II
      • section7-1: 栈、队列重构
        • 1、用队列实现栈
        • 2、用栈实现队列
      • section7-2: 单调栈
        • 1、接雨水
        • 2、柱状图中最大的矩形
        • 3、最大矩形
        • 4、下一个更大元素 I
        • 5、下一个更大元素 II【破环成链】
        • 6、每日温度
      • section7-3: 单调队列
        • 1、滑动窗口最大值
      • section7-4:逆波兰表达式/计算器
        • 1、逆波兰表达式求值
        • 2、基本计算器【×】
        • 3、基本计算器 II
      • section7-5:括号序列
        • 1、有效的括号
        • 2、最长有效括号
    • chap-8:双指针
      • section8.1 同向双指针
        • 1、外观数列【模拟】
        • 2、最后一个单词的长度
        • 3、删除有序数组中的重复项
        • 4、删除有序数组中的重复项 II
        • 5、移除元素
        • 6、颜色分类
        • 7、合并两个有序数组
        • 8、移动零
        • 9、判断子序列
        • 10、字符串中的单词数
        • 11、压缩字符串
        • 12、最大连续 1 的个数
        • 13、划分字母区间[×]
        • 14、按奇偶排序数组 II
        • 15、区间列表的交集
      • section8.2 滑动窗口
        • 1、无重复字符的最长子串
        • 2、最小覆盖子串
        • 3、长度最小的子数组
        • 4、替换后的最长重复字符
        • 5、找到字符串中所有字母异位词
        • 6、数组中的 k-diff 数对
        • 7、字符串的排列
        • 8、最大连续1的个数 III
        • 9、删掉一个元素以后全为 1 的最长子数组
        • 10、删除子数组的最大得分
      • section8.3 逆向双指针
        • 1、最长回文子串
        • 2、盛最多水的容器
        • 3、三数之和
        • 4、最接近的三数之和
        • 5、四数之和
        • 6、验证回文串
        • 7、两数之和 II - 输入有序数组
        • 8、反转字符串
        • 9、反转字符串中的元音字母
    • chap-9:哈希表
        • 1、字母异位词分组
        • 2、最长连续序列
        • 3、存在重复元素
        • 4、存在重复元素 II
        • 5、存在重复元素 III
        • 6、猜数字游戏
        • 7、两个数组的交集
        • 8、两个数组的交集 II
        • 9、O(1) 时间插入、删除和获取随机元素
        • 10、O(1) 时间插入、删除和获取随机元素 - 允许重复
        • 11、赎金信
        • 12、字符串中的第一个唯一字符
        • 13、最长回文串
        • 14、路径总和 III
        • 15、四数相加 II
        • 16、和为 K 的子数组【×】
        • 17、LRU 缓存机制【×】
        • 18、LFU 缓存
        • 19、连续的子数组和【×】前缀和+哈希表
        • 20、连续数组【×】
        • 21、数组中的 k-diff 数对
        • 22、砖墙【×】
        • 23、分糖果
        • 24、设计哈希映射【×】
        • 25、设计哈希集合
        • 26、数的平方等于两数乘积的方法数
        • 27、警告一小时内使用相同员工卡大于等于三次的人
        • 28、字符频次唯一的最小删除次数
        • 29、K 和数对的最大数目
        • 30、同构字符串【双射】
        • 31、单词规律

LeetCode题解

chap-7: 栈、队列

1、最小栈【设计】

class MinStack {
public:
    stack a,b;
    /** initialize your data structure here. */
    MinStack() {
    }    
    void push(int val) {
        a.push(val);
        if(b.empty() || val <= b.top()) b.push(val);
    }    
    void pop() {
        auto t = a.top();
        if(b.size() && b.top() == t) b.pop();
        a.pop();
    }    
    int top() {
        return a.top();
    }    
    int getMin() {
        return b.top();
    }
};

2、比较含退格的字符串

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        stacka,b;
        for(auto c:s){
            if(c == '#'){
                if(a.empty()) continue;
                else a.pop();
            }else a.push(c);
        }
        for(auto c:t){
            if(c == '#'){
                if(b.empty()) continue;
                else b.pop();
            }else b.push(c);
        }
        if(a.size() != b.size()) return false;
        while(a.size()){
            if(a.top() != b.top()) return false;
            a.pop(), b.pop();
        }
        return true;
    }
};

// 进一步地
class Solution {
public:
    string get(string& s) {
        string res;
        for (auto c: s)
            if (c == '#') {
                if (res.size()) res.pop_back();
            } else {
                res += c;
            }
        return res;
    }

    bool backspaceCompare(string s, string t) {
        return get(s) == get(t);
    }
};

3、设计一个支持增量操作的栈 【×】

// inc部分O(k)-O(1)
class CustomStack {
public:
    vecto1r inc_arr;
    stack st;
    int m_size,cnt = 0;
    CustomStack(int maxSize) {
        m_size = maxSize;
        inc_arr.resize(maxSize + 1,0);
    }

    void push(int x) {
        if(cnt < m_size){
            cnt ++;
            st.push(x);
        }
    }

    int pop() {
        if(cnt == 0)
            return -1;
        int p = st.top();
        st.pop();
        if(inc_arr[cnt] != 0){
            inc_arr[cnt - 1] += inc_arr[cnt];
            p += inc_arr[cnt];
            inc_arr[cnt] = 0;
        }
        cnt --;
        return p;
    }

    void increment(int k, int val) {
        inc_arr[min(k,cnt)] += val;
    }
};

4、设计循环队列

class MyCircularQueue {
public:
    int hh = 0, tt = 0;
    vector q;

    /** Initialize your data structure here. Set the size of the queue to be k. */
    MyCircularQueue(int k) {
        q.resize(k + 1);
    }

    /** Insert an element into the circular queue. Return true if the operation is successful. */
    bool enQueue(int value) {
        if (isFull()) return false;
        q[tt ++ ] = value;
        if (tt == q.size()) tt = 0;
        return true;
    }

    /** Delete an element from the circular queue. Return true if the operation is successful. */
    bool deQueue() {
        if (isEmpty()) return false;
        hh ++ ;
        if (hh == q.size()) hh = 0;
        return true;
    }

    /** Get the front item from the queue. */
    int Front() {
        if (isEmpty()) return -1;
        return q[hh];
    }

    /** Get the last item from the queue. */
    int Rear() {
        if (isEmpty()) return -1;
        int t = tt - 1;
        if (t < 0) t += q.size();
        return q[t];
    }

    /** Checks whether the circular queue is empty or not. */
    bool isEmpty() {
        return hh == tt;
    }

    /** Checks whether the circular queue is full or not. */
    bool isFull() {
        return (tt + 1) % q.size() == hh;
    }
};

5、设计循环双端队列

class MyCircularDeque {
public:
    int hh = 0, tt = 0;
    vector q;

    /** Initialize your data structure here. Set the size of the deque to be k. */
    MyCircularDeque(int k) {
        q.resize(k + 1);
    }

    int get(int x) {
        return (x + q.size()) % q.size();
    }

    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    bool insertFront(int value) {
        if (isFull()) return false;
        hh = get(hh - 1);
        q[hh] = value;
        return true;
    }

    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    bool insertLast(int value) {
        if (isFull()) return false;
        q[tt ++ ] = value;
        tt = get(tt);
        return true;
    }

    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    bool deleteFront() {
        if (isEmpty()) return false;
        hh = get(hh + 1);
        return true;
    }

    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    bool deleteLast() {
        if (isEmpty()) return false;
        tt = get(tt - 1);
        return true;
    }

    /** Get the front item from the deque. */
    int getFront() {
        if (isEmpty()) return -1;
        return q[hh];
    }

    /** Get the last item from the deque. */
    int getRear() {
        if (isEmpty()) return -1;
        return q[get(tt - 1)];
    }

    /** Checks whether the circular deque is empty or not. */
    bool isEmpty() {
        return hh == tt;
    }

    /** Checks whether the circular deque is full or not. */
    bool isFull() {
        return get(hh - 1) == tt;
    }
};

6、验证栈序列

class Solution {
public:
    bool validateStackSequences(vector& pushed, vector& popped) {
        stack s; int j = 0;
        for(int i = 0;i

7、删除字符串中的所有相邻重复项

class Solution {
public:
    string removeDuplicates(string s) {
        string stk;
        for(auto &c:s){
            if(stk.size() && stk.back() == c) stk.pop_back();
            else stk.push_back(c);
        }        
        return stk;
    }
};

8、删除字符串中的所有相邻重复项 II

class Solution {
public:
    string removeDuplicates(string s, int k) {
        string stk("#");
        stack cnt;
        cnt.push(1);
        for(int i = 0 ; i < s.size() ; i++) {
            if(s[i] == stk.back()) cnt.push(cnt.top()+1);
            else cnt.push(1);

            stk += s[i];

            if(cnt.top() >= k) {
                for(int j = 0 ; j < k ; j++) {
                    stk.pop_back();
                    cnt.pop();
                }
            }
        }
        return stk.substr(1);
    }
};

[Go Back~~](# LeetCode题解)

section7-1: 栈、队列重构

1、用队列实现栈

class MyStack {
public:
    /** Initialize your data structure here. */
    queue a,b;
    MyStack() {

    }
    
    /** Push element x onto stack. */
    void push(int x) {
        a.push(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        while(a.size() > 1) b.push(a.front()), a.pop();
        int t = a.front(); a.pop();
        while(b.size()) a.push(b.front()), b.pop();
        return t;
    }
    
    /** Get the top element. */
    int top() {
        while(a.size() > 1) b.push(a.front()), a.pop();
        int t = a.front(); b.push(a.front()), a.pop();
        while(b.size()) a.push(b.front()), b.pop();
        return t;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return a.empty();
    }
};

2、用栈实现队列

class MyQueue {
public:
    /** Initialize your data structure here. */
    stack a,b;
    MyQueue() {

    }
    
    void in2out(){
        while(a.size()) b.push(a.top()), a.pop();
    }

    /** Push element x to the back of queue. */
    void push(int x) {
        a.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if(b.empty()) in2out();
        int t = b.top(); b.pop();
        return t;
    }
    
    /** Get the front element. */
    int peek() {
        if(b.empty()) in2out();
        return b.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return a.empty() && b.empty();
    }
};

section7-2: 单调栈

1、接雨水

class Solution {
public:
    int trap(vector& h) {
        stack help;
        int ans = 0;
        for(int i=0;i top()
                    auto t = help.top(); help.pop();
                    while(help.size() && h[t] <= h[i]){
                        auto q = help.top(); 
                        if(h[q] <= h[i]) help.pop();
                        ans += (min(h[q],h[i]) - h[t])*(i-q-1);
                        t = q;
                    }
                    help.push(i);
                }
            }
        }
        return ans;
    }
};

// 逻辑优化
class Solution {
public:
    int trap(vector& h) {
        stack help;
        int ans = 0;
        for(int i=0;i

2、柱状图中最大的矩形

class Solution {
public:
    int largestRectangleArea(vector& h) {
        int ans = 0; h.push_back(-1);
        stack s;
        for(int i=0;i

3、最大矩形

class Solution {
public:
    int maximalRectangle(vector>& matrix) {
        if(matrix.size() <= 0) return 0;
        int ans = 0, m = matrix.size(), n = matrix[0].size();
        vectorhelp = vector(n+1,0);
        for(int i=0;i s;
            for(int j=0;j<=n;j++){
                while(s.size() && help[j] < help[s.top()]){
                    auto t = s.top(); s.pop();
                    if(s.empty()) ans = max(ans,help[t]*j);
                    else ans = max(ans,help[t]*(j-s.top()-1));
                }
                s.push(j);
            }
        }
        return ans;
    }
};

4、下一个更大元素 I

class Solution {
public:
    vector nextGreaterElement(vector& nums1, vector& nums2) {
        unordered_maphash;
        stack s;
        for(int i=nums2.size()-1;~i;i--){
            if(s.empty()) hash[nums2[i]] = -1, s.push(nums2[i]);
            else{
                while(s.size() && nums2[i] > s.top()){
                    s.pop();
                    if(s.empty()) {
                        hash[nums2[i]] = -1, s.push(nums2[i]);
                        break;
                    }
                }
                if(nums2[i] < s.top()) hash[nums2[i]] = s.top(), s.push(nums2[i]);
            }                
        }
        vector ans;
        for(auto &num:nums1) ans.push_back(hash[num]);
        return ans;
    }
};

5、下一个更大元素 II【破环成链】

class Solution {
public:
    vector nextGreaterElements(vector& nums) {
        int n = nums.size();
        vector ans(n,0);
        nums.insert(nums.end(),nums.begin(),nums.end());
        stack s;
        for(int i = 2*n-1;~i;i--){
            int x = nums[i];
            while(s.size() && x >= s.top()) s.pop();
            if(i

6、每日温度

class Solution {
public:
    vector dailyTemperatures(vector& t) {
        stack s; int n = t.size();
        vector ans(n);
        for(int i=n-1;~i;i--){
            while(s.size() && t[i] >= t[s.top()]) s.pop();
            if(s.empty()){
                ans[i] = 0;
            }else ans[i] = s.top()-i;
            s.push(i);
        }
        return ans;
    }
};

[Go Back~~](# LeetCode题解)

section7-3: 单调队列

1、滑动窗口最大值

class Solution {
public:
    vector maxSlidingWindow(vector& nums, int k) {
        deque q;
        vector ans;
        for(int i = 0;i q.front()) q.pop_front();            
            while(q.size() && nums[q.back()] <= nums[i]) q.pop_back();
            q.push_back(i);
            if(i>=k-1) ans.push_back(nums[q.front()]);
        }
        return ans;
    }
};

section7-4:逆波兰表达式/计算器

1、逆波兰表达式求值

class Solution {
public:
    int evalRPN(vector& tokens) {
        stack s;
        for(auto &t:tokens){
            if(t == "+" || t == "-" || t == "*" || t == "/"){
                int a = s.top(); s.pop();
                int b = s.top(); s.pop();
                if(t == "+") s.push(b+a);
                if(t == "-") s.push(b-a);
                if(t == "*") s.push(b*a);
                if(t == "/") s.push(b/a);
            }else{
                s.push(stoi(t));
            }
        }
        return s.top();
    }
};

2、基本计算器【×】

class Solution {
public:
    void eval(stack& num,stack& op)
    {
        auto b=num.top();num.pop();
        auto a=num.top();num.pop();
        auto c=op.top();op.pop();
        if(c=='+') num.push(a+b);
        else num.push(a-b);
    }

    int calculate(string rs) {
        string s;
        for(auto c:rs)
            if(c!=' ')
                s+=c;

        stack num;
        stack op;
        for(int i=0;i

3、基本计算器 II

class Solution {
public:
    int calculate(string s) {
        char pre = '+';
        vector help;
        for(int i = 0;i

section7-5:括号序列

1、有效的括号

class Solution {
public:
    bool isValid(string s) {
        stack stk;
        for(auto c:s){
            if(c == '(' || c == '[' || c == '{') stk.push(c);
            else{
                if(stk.size()){
                    auto t = stk.top();
                    if(c-t==')'-'(' || c-t==']'-'[' || c-t=='}'-'{')
                        stk.pop();
                    else return false;                   
                } else return false;                    
            }
        }
        return stk.empty();
    }
};

2、最长有效括号

class Solution {
public:
    int longestValidParentheses(string s) {
        stack stk; // 记录左括号位置
        int start = 0, ans = 0;
        for(int i = 0;i

[Go Back~~](# LeetCode题解)

chap-8:双指针

section8.1 同向双指针

1、外观数列【模拟】

class Solution {
public:
    string countAndSay(int n) {
        string ans = "1";
        while(--n){
            string temp;
            for(int i = 0;i

2、最后一个单词的长度

class Solution {
public:
    int lengthOfLastWord(string s) {
        int n = s.length() - 1;
        while(n >=0 && s[n] == ' ') n--;
        int i = n;
        while(~i && s[i] != ' ') i--;
        return i>=0 ? n-i:n+1;
    }
};

3、删除有序数组中的重复项

class Solution {
public:
    int removeDuplicates(vector& nums) {
        if(nums.empty()) return 0;
        int j=0;
        for(int i=j+1;i

4、删除有序数组中的重复项 II

class Solution {
public:
    int removeDuplicates(vector& nums) {
        if(nums.empty()) return 0;
        int j=0;
        for(int i = j+1;i

5、移除元素

class Solution {
public:
    int removeElement(vector& nums, int val) {
        if(nums.empty()) return 0;
        int len = 0;
        for(int i=len;i

6、颜色分类

class Solution {
public:
    void sortColors(vector& nums) {
        int l=-1,r=nums.size();
        for(int i=0;i

7、合并两个有序数组

class Solution {
public:
    void merge(vector& nums1, int m, vector& nums2, int n) {
        int i = m-1, j = n-1, k = m+n-1;
        while(~i && ~j){
            if(nums1[i] > nums2[j]) nums1[k--] = nums1[i--];
            else nums1[k--] = nums2[j--];
        }
        while(~i) nums1[k--] = nums1[i--];
        while(~j) nums1[k--] = nums2[j--];
    }
};

8、移动零

class Solution {
public:
    void moveZeroes(vector& nums) {
        int i = 0;
        while(i

9、判断子序列

class Solution { // 双指针
public:
    bool isSubsequence(string t, string s) {
        int i = 0, j = 0;
        while(i> f(m+1, vector(26,0));
        for(int i = 0;i<26;i++) f[m][i] = m;
        for(int i = m-1;i>=0;i--){
            for(int j = 0;j<26;j++){
                if(j == t[i]-'a') f[i][j] = i;
                else f[i][j] = f[i+1][j];
            }
        }
        int idx = 0; // f起始处开始搜
        for (int i = 0; i < n; i++) {
            if (f[idx][s[i] - 'a'] == m) {
                return false;
            }
            idx = f[idx][s[i] - 'a'] + 1; // 下一个位置
        }
        return true;
    }
};

10、字符串中的单词数

// 库函数
class Solution {
public:
    int countSegments(string s) {
        stringstream sin(s);
        int ans = 0; string c;
        while(sin>>c) ans++;
        return ans;
    }
};

// 双指针
class Solution {
public:
    int countSegments(string s) {
        int res = 0;
        for(int i = 0;i

11、压缩字符串

class Solution {
public:
    int compress(vector& chars) {
        int ans = 0;
        for(int i = 0;i 1) {
                i = j-1;
                string s = to_string(t);                
                for(j=0;j

12、最大连续 1 的个数

class Solution {
public:
    int findMaxConsecutiveOnes(vector& nums) {
        int ans = 0;
        for(int i=0;i

13、划分字母区间[×]

class Solution {
public:
    vector partitionLabels(string s) {
        unordered_map hash;
        int i = 0,start = 0,end = 0;
        vector ans;
        for(;i

14、按奇偶排序数组 II

class Solution {
public:
    vector sortArrayByParityII(vector& nums) {
        int slow = 0, fast = slow+1;
        while(true){
            while(slow < nums.size() && nums[slow]%2 == 0) slow+=2;
            while(fast < nums.size() && nums[fast]%2) fast+=2;
            if(fast >= nums.size()) break;
            else{
                swap(nums[slow],nums[fast]);
            }
        }
        return nums;
    }
};

15、区间列表的交集

class Solution {
public:
    vector> intervalIntersection(vector>& f, vector>& s) {
        vector> ans;
        for(int i = 0,j = 0;i= s[j][0])
                ans.push_back({max(f[i][0],s[j][0]),min(f[i][1],s[j][1])});
            if(f[i][1] <= s[j][1]) i++;
            else j++;
        }
        return ans;
    }
};

[Go Back~~](# LeetCode题解)

section8.2 滑动窗口

1、无重复字符的最长子串

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ans = 0;
        unordered_map hash;
        for(int last = 0, cur = 0;cur < s.size();cur++){
            hash[s[cur]]++;
            while(hash[s[cur]] == 2){
                hash[s[last++]]--;
            }
            ans = max(ans,cur-last+1);
        }
        return ans;
    }
};

2、最小覆盖子串

class Solution {
public:
    string minWindow(string s, string t) {
        string ans = "";
        unordered_map hash;
        int cnt = 0;
        for(auto c:t) {
            if(!hash[c]) cnt++;
            hash[c]++;
        }
        for(int i=0,j=0,c=0;i i-j+1) ans = s.substr(j,i-j+1);
            }
        }
        return ans;
    }
};

3、长度最小的子数组

class Solution {
public:
    int minSubArrayLen(int target, vector& nums) {
        int ans = 0;
        for(int i=0,j=0,t=0;i= target) {
                ans = ans == 0?i-j+1: min(ans,i-j+1);
                t-=nums[j++];
                if(t >= target) ans = ans == 0?i-j+1: min(ans,i-j+1);
            }
        }
        return ans;
    }
};

4、替换后的最长重复字符

class Solution {
public:
    int characterReplacement(string s, int k) {
        int ans = 0;
        for (char c='A'; c<='Z'; c++){
            for(int i=0,j=0,cnt=0;i k){
                    if(s[j] == c) cnt--;
                    j++;
                }
                ans = max(ans, i-j+1);
            }
        }        
        return ans;
    }
};

5、找到字符串中所有字母异位词

class Solution {
public:
    vector findAnagrams(string s, string p) {
        int m=s.size(),n=p.size();
        vector res;
        if(n>m) return res;
        unordered_map hash;
        for(auto&c:p)hash[c]++;
        int tot = hash.size();
        for(int i=0,j=0,k=0;i p.size()){
                if(hash[s[j]] == 0) k--;
                hash[s[j++]]++;
            }
            if(k == tot) res.push_back(j);
        }
        return res;
    }
};

6、数组中的 k-diff 数对

// O(n)
class Solution {
public:
    int findPairs(vector& nums, int k) {
        if(k<0) return 0;
        unordered_set first_ele, hash;
        for(int i=0;i& nums, int k) {
        int ans = 0;
        sort(nums.begin(), nums.end());
        for(int i=0,j=0;i k) j++;
            if(j < i && nums[i] - nums[j] == k) ans++;
        }
        return ans;
    }
};

7、字符串的排列

class Solution {
public:
    bool checkInclusion(string s1, string s) {
        unordered_map hash;
        for(auto c:s1) hash[c]++;
        int tot = hash.size();
        for(int i=0, j=0, cnt = 0; i s1.size()){
                if(hash[s[j]] == 0) cnt--;
                hash[s[j++]]++;
            }
            if(cnt == tot) return true;
        }
        return false;
    }
};

8、最大连续1的个数 III

class Solution {
public:
    int longestOnes(vector& nums, int k) {
        int ans=0;
        for(int i=0,j=0,cnt=0;i k){
                if(nums[j++] == 1) cnt--;
            }
        }
        return ans;
    }
};

9、删掉一个元素以后全为 1 的最长子数组

class Solution {
public:
    int longestSubarray(vector& nums) {
        int res = 0;
        for(int l = 0 ,r = 0, cnt = 0;r1){
                if(nums[l]==0){
                    cnt--;
                }
                l++;
            }
            res = max(res,r-l+1);
        }
        return res-1;
    }
};

10、删除子数组的最大得分

class Solution {
public:
    int maximumUniqueSubarray(vector& nums) {
        int ans = 0;
        unordered_map hash;
        for(int i=0,j=0,tot=0;i

[Go Back~~](# LeetCode题解)

section8.3 逆向双指针

1、最长回文子串

class Solution {
public:
    string longestPalindrome(string s) {
        vector t = {0,0};
        for(int i = 0;i= 0 && r < s.size() && s[l] == s[r]){
                if(t[1] - t[0] < (r-l+1)){
                    t[0] = l; t[1] = r;                    
                }
                l--; r++;
            }
            l = i-1;r = i;
            while(l >= 0 && r < s.size() && s[l] == s[r]){
                if(t[1] - t[0] < (r-l+1)){
                    t[0] = l; t[1] = r;                    
                }
                l--; r++;
            }
        }
        return s.substr(t[0],t[1] - t[0] + 1);
    }
};

2、盛最多水的容器

class Solution {
public:
    int maxArea(vector& height) {
        int l = 0, r = height.size()-1, res = 0;
        while(l

3、三数之和

class Solution {
public:
    vector> threeSum(vector& nums) {
        vector> res;
        if(nums.size() < 3) return res;
        sort(nums.begin(),nums.end());
        for(int i = 0;i 0 - nums[i]) k--;
                    else {
                        res.push_back({nums[i],nums[j],nums[k]});
                        j++;
                    }
                }                
            }
        }
        return res;
    }
};

4、最接近的三数之和

class Solution {
public:
    int threeSumClosest(vector& nums, int target) {
        pair pii(INT_MAX,INT_MAX);
        sort(nums.begin(),nums.end());
        for(int i = 0;i target){
                    k--;
                    pii = min(pii,make_pair(abs(target - t),t));
                }else return target;
            }
        }
        return pii.second;
    }
};

5、四数之和

class Solution {
public:
    vector> fourSum(vector& nums, int target) {
        vector> res;
        if(nums.size() < 4) return res;
        sort(nums.begin(),nums.end());
        for(int  i = 0;i

6、验证回文串

class Solution {
public:
    bool isPalindrome(string s) {
        int l = 0, r = s.size()-1;
        while(l

7、两数之和 II - 输入有序数组

class Solution {
public:
    vector twoSum(vector& numbers, int target) {
        for(int i = 0,j = numbers.size()-1;i target) j--;
            if(numbers[i] + numbers[j] < target) i++;
            if(numbers[i] + numbers[j] == target) return{i+1,j+1};
        }
        return {-1,-1};
    }
};

8、反转字符串

class Solution {
public:
    void reverseString(vector& s) {
        for(int l = 0, r = s.size()-1;l

9、反转字符串中的元音字母

class Solution {
public:
    bool is(char c) {
        if(c=='a' || c=='e' || c=='i' || c=='o' || c=='u' ||
        c=='A' || c=='E' || c=='I' || c=='O' || c=='U' )
        return true;
        else return false;
    }
    string reverseVowels(string s) {
        string ans = s;
        for(int l=0,r=s.size()-1;ll && !is(ans[r])) r--;
            swap(ans[l], ans[r]);
            l++; r--;
        }
        return ans;
    }
};

[Go Back~~](# LeetCode题解)

chap-9:哈希表

1、字母异位词分组

class Solution {
public:
    vector> groupAnagrams(vector& strs) {
        unordered_map> hash;
        for(auto &str:strs){
            string s = str;
            sort(s.begin(),s.end());
            if(hash.find(s) != hash.end()){
                hash[s].emplace_back(str);
            }else{
                hash[s] = vector({str});
            }
        }
        vector> ans;
        for(auto &iter:hash){
            ans.emplace_back(iter.second);
        }
        return ans;
    }
};

2、最长连续序列

class Solution {
public:
    int longestConsecutive(vector& nums) {
        unordered_set s(nums.begin(),nums.end());
        int ans = 0;
        for(auto& num:s){
            if(s.find(num - 1) == s.end()){
                int st = num;
                while(s.find(++st) != s.end());
                ans = max(st - num,ans);
            }
        }
        return ans;
    }
};

// 法2
class Solution {
public:
    int longestConsecutive(vector& nums) {
        unordered_map right,left;
        int ans = 0;
        for(auto &num:nums){
            int l = right[num-1]; // right:表示以x为右终点
            int r = left[num+1]; // left:表示以x为左起点
            right[num+r] = max(right[num+r], l+r+1);
            left[num-l] = max(left[num-l], l+r+1);
            ans = max(ans, l+r+1);
        }
        return ans;
    }
};

3、存在重复元素

class Solution {
public:
    bool containsDuplicate(vector& nums) {
        unordered_set v;
        for (int i = 0; i < nums.size(); i++) {
            if (v.find(nums[i]) != v.end())
                return true;
            v.insert(nums[i]);
        }
        return false;
    }
};

4、存在重复元素 II

class Solution {
public:
    bool containsNearbyDuplicate(vector& nums, int k) {
        unordered_map hash;
        for(int i=0;i

5、存在重复元素 III

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) {
        typedef long long ll;
        multiset hash;
        hash.insert(1e18); hash.insert(-1e18);
        for(int i=0,j=0;i k){
                hash.erase(hash.find(nums[j++]));
            }
            int x = nums[i];
            auto it = hash.lower_bound(x);
            if(*it - x <= t) return true;
            it--;
            if(x - *it <= t) return true;
            hash.insert(x);
        }
        return false;
    }
};

6、猜数字游戏

class Solution {
public:
    string getHint(string secret, string guess) {
        unordered_map hash;
        for(auto c:secret) hash[c]++;
        int tot=0, bulls=0;
        for(int i=0;i

7、两个数组的交集

class Solution {
public:
    vector intersection(vector& nums1, vector& nums2) {
        unordered_set n1(nums1.begin(), nums1.end());
        vector ans;
        for(auto x:nums2){
            if(n1.count(x)) {
                ans.push_back(x);
                n1.erase(x);
            }
        }
        return ans;
    }
};

8、两个数组的交集 II

class Solution {
public:
    vector intersect(vector& nums1, vector& nums2) {
        unordered_multiset S;
        vector res;
        for (int x : nums1) S.insert(x);
        for (int x : nums2)
            if (S.count(x))
            {
                res.push_back(x);
                S.erase(S.find(x));
            }
        return res;
    }
};

9、O(1) 时间插入、删除和获取随机元素

class RandomizedSet {
public:
    vector temp;
    unordered_map hash;
    int cnt = 0;
    RandomizedSet() {
    }
    
    bool insert(int val) {
        if(hash.find(val) == hash.end()){
            hash[val] = cnt++;
            temp.push_back(val);
            return true;
        }
        else return false;
    }
    
    bool remove(int val) {
        auto it = hash.find(val);
        if(it != hash.end()){
            int idx = it->second;
            temp[idx] = temp.back();
            hash[temp[idx]] = idx;
            temp.pop_back();
            cnt--;
            hash.erase(it);
            return true;
        }else return false;

    }
    
    int getRandom() {
        return temp[rand()%cnt];
    }
};

10、O(1) 时间插入、删除和获取随机元素 - 允许重复

class RandomizedCollection {
public:
    vector num;
    unordered_map> hash;
    RandomizedCollection() {

    }
    
    bool insert(int val) {
        bool f = hash.find(val) == hash.end();
        num.push_back(val);
        hash[val].insert(num.size()-1);
        return f;
    }
    
    bool remove(int val) {
        if(hash.find(val) != hash.end()){
            if(num.back() == val){
                hash[val].erase(hash[val].find(num.size()-1));
                num.pop_back();
                if (hash[val].empty())
                    hash.erase(val);
                return true;
            }

            int t = *hash[val].begin();

            hash[num.back()].erase(num.size() - 1);
            hash[num.back()].insert(t);

            swap(num[t], num.back());

            num.pop_back();
            hash[val].erase(t);
            if (hash[val].empty())
                hash.erase(val);
            return true;
        }
        return false;
    }
    
    int getRandom() {
        return num[rand() % num.size()];
    }
};

11、赎金信

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        if(magazine.size() < ransomNote.size()) return false;
        unordered_map hash;
        for(auto c:magazine) hash[c]++;
        for(auto c:ransomNote){
            if(hash[c] == 0) return false;
            else hash[c]--;
        }
        return true;
    }
};

12、字符串中的第一个唯一字符

class Solution {
public:
    int firstUniqChar(string s) {
        unordered_map hash;
        for(auto c:s) hash[c]++;
        for(int i=0;i

13、最长回文串

class Solution {
public:
    int longestPalindrome(string s) {
        unordered_map hash;
        for(auto c:s) hash[c]++;
        int ans = 0;
        bool f = false;
        for(auto &it:hash){
            if(it.second % 2){
                if(!f) f = true;
                ans+=it.second-1;
            }else ans+=it.second;
        }
        if(f) return ans+1;
        else return ans;
    }
};

14、路径总和 III

class Solution {
public:
    int res = 0;
    unordered_map cnt;
    int pathSum(TreeNode* root, int t) {
        cnt[0] = 1;
        dfs(root,t,0);
        return res;
    }
    void dfs(TreeNode*root,int t,int cur_sum){
        if(root == nullptr) return;
        cur_sum += root->val;
        res += cnt[cur_sum - t];
        cnt[cur_sum]++;
        dfs(root->left,t,cur_sum);
        dfs(root->right,t,cur_sum);
        cnt[cur_sum]--;
    }
};

15、四数相加 II

class Solution {
public:
    int fourSumCount(vector& nums1, vector& nums2, vector& nums3, vector& nums4) {
        unordered_map hash;
        for(int i=0;i

16、和为 K 的子数组【×】

class Solution {
public:
    int subarraySum(vector& nums, int k) {
        int ans=0,tot=0;
        unordered_map hash;
        hash[0]=1;
        for(auto &x:nums){
            tot+=x;
            ans+=hash[tot-k];
            hash[tot]++;
        }
        return ans;
    }
};

//通俗做法-超时O(n2)
class Solution {
public:
    int subarraySum(vector& nums, int k) {
        int ans = 0;
        for(int i=0;i=0;j--){
                sum+=nums[j];
                if(sum == k) ans++;
            }
        }
        return ans;
    }
};

17、LRU 缓存机制【×】

class LRUCache {
public:
    struct Node{
        int key, val;
        Node* left;
        Node* right;
        Node(int _key, int _val): key(_key), val(_val), left(nullptr), right(nullptr){}
    }*L, *R;
    unordered_map hash;
    int n;

    void remove(Node *p){
        p->left->right = p->right;
        p->right->left = p->left;
    }

    void insert(Node *p){        
        p->right = L->right;
        p->left = L;
        L->right->left = p;
        L->right = p;
    }

    LRUCache(int capacity) {
        n = capacity;
        L = new Node(-1,-1);
        R = new Node(-1,-1);
        L->right = R;
        R->left = L;
    }
    
    int get(int key) {
        if(hash.find(key) == hash.end()) return -1;
        auto p = hash[key];
        remove(p); // 先后顺序搞清
        insert(p);
        return p->val;
    }
    
    void put(int key, int value) {
        if(hash.find(key)!=hash.end()){
            auto p = hash[key];
            p->val = value;
            remove(p);
            insert(p);

        }else{
            if(hash.size() == n){
                auto p = R->left;
                remove(p);
                hash.erase(p->key);
                delete p;
            }
            auto q = new Node(key, value);
            insert(q);
            hash[key] = q;
        }
    }
};

18、LFU 缓存

class LFUCache {
public:
    struct Node{
        Node *left, *right;
        int key, val;
        Node(int _key,int _val):key(_key), val(_val), left(NULL), right(NULL){}
    };

    struct Block{
        Block *left,*right;
        Node *head,*tail;
        int cnt;
        ~Block(){
            delete head;
            delete tail;
        }
        Block(int _cnt){
            cnt = _cnt;
            left = right = NULL;
            head = new Node(-1,-1);
            tail = new Node(-1,-1);
            head->right = tail, tail->left = head;
        }
        void insert(Node *p){
            p->right = head->right;
            head->right->left = p;
            p->left = head;
            head->right = p;
        }
        void remove(Node *p){
            p->left->right = p->right;
            p->right->left = p->left;
        }
        bool empty(){
            return head->right == tail;
        }
    }*head,*tail;
    int n;
    unordered_map hash_block;
    unordered_map hash_node;

    void insert(Block *p){   // 在p的右侧插入新块,cnt是p->cnt + 1
        auto cur = new Block(p->cnt + 1);
        cur->right = p->right;
        p->right->left = cur;
        p->right = cur;
        cur->left = p;
    }

    void remove(Block* p) {
        p->left->right = p->right;
        p->right->left = p->left;
        delete p;
    }

    LFUCache(int capacity) {
        n = capacity;
        head = new Block(0), tail = new Block(INT_MAX);
        head->right = tail, tail->left = head;
    }
    
    int get(int key) {
        if(hash_block.find(key) == hash_block.end()) return -1;
        auto block = hash_block[key];
        auto node = hash_node[key];
        block->remove(node);
        if (block->right->cnt != block->cnt + 1) insert(block);
        block->right->insert(node);
        hash_block[key] = block->right;
        if (block->empty()) remove(block);
        return node->val;
    }
    
    void put(int key, int value) {
        if(!n) return; // 特例
        if(hash_block.find(key) != hash_block.end()){
            hash_node[key]->val = value;
            get(key);
        }
        else{
            if (hash_block.size() == n) {
                auto p = head->right->tail->left;
                head->right->remove(p);
                if (head->right->empty()) remove(head->right);
                hash_block.erase(p->key);
                hash_node.erase(p->key);
                delete p;
            }
            auto p = new Node(key, value);
            if (head->right->cnt > 1) insert(head);
            head->right->insert(p);
            hash_block[key] = head->right;
            hash_node[key] = p;
        }
    }
};

19、连续的子数组和【×】前缀和+哈希表

class Solution {
public:
    bool checkSubarraySum(vector& nums, int k) {
        int n = nums.size();
        vector s(n+1);
        for(int i=1;i<=n;i++) s[i] = s[i-1]+nums[i-1];
        unordered_set hash;
        for(int i =2;i<=n;i++){
            hash.insert(s[i-2]%k);
            if(hash.count(s[i]%k)) return true;
        }
        return false;
    }
};

20、连续数组【×】

class Solution {
public:
    int findMaxLength(vector& nums) {
        int ans = 0;
        unordered_maphash;
        hash[0] = 0;
        for(int i=1,x=0;i<=nums.size();i++){
            x+=(nums[i-1] == 1?1:-1);
            if(hash.count(x)) ans = max(ans,i-hash[x]);
            else hash[x]=i;
        }
        return ans;
    }
};

21、数组中的 k-diff 数对

class Solution {
public:
    int findPairs(vector& nums, int k) {
        unordered_set hash, ele;
        for(int i=0;i

22、砖墙【×】

class Solution {
public:
    int leastBricks(vector>& wall) {
        int width = accumulate(wall[0].begin(), wall[0].end(), 0);
        unordered_map hash;
        int sum;
        for(auto &a:wall){
            sum = 0;
            for(auto& b:a)
                sum+=b, hash[sum]++;
        }
        sum=0;
        for(auto &it:hash){
            if(it.first != width)
                sum = max(sum,it.second);
        }
        return wall.size() - sum;
    }
};

23、分糖果

class Solution {
public:
    int distributeCandies(vector& candyType) {
        unordered_set hash(candyType.begin(), candyType.end());
        return min(candyType.size()/2, hash.size());
    }
};

24、设计哈希映射【×】

// 开放寻址法
class MyHashMap {
public:
    const static int N=20011;
    int hash_key[N], hash_val[N];

    MyHashMap() {
        memset(hash_key,-1,sizeof(hash_key));
    }
    
    int find(int key){
        int t = key%N;
        while(hash_key[t] != key && hash_key[t] != -1) 
            if(++t == N) 
                t = 0;
        return t;
    }

    void put(int key, int value) {
        int t = find(key);
        hash_key[t] = key;
        hash_val[t] = value;        
    }
    
    int get(int key) {
        int t = find(key);
        if(hash_key[t] == -1) return -1;
        return hash_val[t];
    }
    
    void remove(int key) {
        int t = find(key);
        if (hash_key[t] != -1)
            hash_key[t] = -2;
    }
};

25、设计哈希集合

// 拉链法
class MyHashSet {
public:
    const static int N = 20011;
    vector help[N];

    MyHashSet() {

    }
    
    int find(vector&h, int key){
        for(int i=0;i

26、数的平方等于两数乘积的方法数

class Solution {
public:
    int numTriplets(vector& nums1, vector& nums2) {
        typedef long long ll;
        unordered_map hash;
        for(auto num:nums1) hash[(ll)num*num]++;
        int ans = 0;
        for(int i=0;i=0;j--){
                if(hash.count((ll)nums2[i]*nums2[j]))
                    ans+=hash[(ll)nums2[i]*nums2[j]];
            }
        }
        unordered_map hash1;
        for(auto num:nums2) hash1[(ll)num*num]++;
        for(int i=0;i=0;j--){
                if(hash1.count((ll)nums1[i]*nums1[j]))
                    ans+=hash1[(ll)nums1[i]*nums1[j]];
            }
        }
        return ans;
    }
};

27、警告一小时内使用相同员工卡大于等于三次的人

class Solution {
public:
    vector alertNames(vector& keyName, vector& keyTime) {
        unordered_map> hash;
        for(int i=0;i ans;
        for(auto &it:hash){
            sort(it.second.begin(),it.second.end());
            for(int i=2;i

28、字符频次唯一的最小删除次数

class Solution {
public:
    int minDeletions(string s) {
        vector help(26);
        for(auto c:s) help[c-'a']++;
        sort(help.rbegin(), help.rend());
        int ans = 0;
        for(int i=0;i help[i+1]) continue;
            if(help[i] == 0){
                ans += help[i+1];
                help[i+1] = 0;
            }else{
                int a = help[i]-1;
                ans += help[i+1] - a;
                help[i+1] = a;
            }
        }
        return ans;
    }
};

29、K 和数对的最大数目

class Solution {
public:
    int maxOperations(vector& nums, int k) {
        unordered_map hash;
        for(auto t:nums) hash[t]++;
        int ans = 0;
        for(auto &t:hash){
            if(hash.find(k - t.first) != hash.end()){
                if(k - t.first == t.first) ans += t.second-1;
                else ans += min(t.second, hash[k - t.first]);
            }
        }
        return (ans+1)/2; // 
    }
};

30、同构字符串【双射】

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        unordered_map hashs;
        unordered_map hasht;
        for(auto i=0;i

31、单词规律

class Solution {
public:
    bool wordPattern(string t, string s) {
        stringstream sstream(s);
        unordered_map ts;
        unordered_map st;
        int i = 0;
        while(sstream){
            string tt;
            sstream>>tt;
            if(ts.count(t[i])){
                if(ts[t[i]] != tt) return false;
            }else ts[t[i]] = tt;

            if(st.count(tt)){
                if(st[tt] != t[i]) return false;
            }else st[tt] = t[i];
            i++;
        }
        return i == (t.size()+1);
    }
};

[Go Back~~](# LeetCode题解)