基础

二分查找

    int search(vector<int>& nums, int target) {
        
        int left = 0;
        int right = nums.size()-1;
        
        while(left <= right) {
            int mid = left + (right-left)/2;
            if(nums[mid] < target) {
                left = mid+1;
            } else if(nums[mid] > target) {
                right = mid-1;
            } else {
                return mid;
            }
        }
        
        return -1;
}

快速排序

void quickSort(vector<int>& vec,int i,int j){
  if(j-i<=0){
    return;
  }
  int k=i;
  int end = j;
  while(i!=j){
    while(vec[j]>vec[k]){
      j--;
    }
    while(i!=j && vec[i]<=vec[k]){
      i++;
    }
    swap(vec[i],vec[j]);
  }
  swap(vec[i],vec[k]);
  quickSort(vec,k,i-1);
  quickSort(vec,i+1,end);
}

动态数组 扩容拷贝删除原有内存

#include <iostream>
#include <memory>
#include <string>
using namespace std;
template <class T>
class myvector {
public:
  using iterator = T *;
  myvector() = default;
  myvector(int size, const T &value) {
    expand(size);
    for (int i = 0; i < size; i++) {
      alloc.construct(_end, value);
      _end++;
    }
  }
  ~myvector() { free(); }

  iterator begin() const { return _begin; }
  iterator end() const { return _end; }
  size_t size() const { return _end - _begin; }
  void reserve(unsigned int size) {
    if (_cap - _begin < size) {
      expand(size);
    }
  }
  void push_back(const T &value) {
    check_and_expand();
    alloc.construct(_end, value);
    _end++;
  }
  void pop_back() {
    if (_end > _begin) {
      alloc.destroy(_end);
      _end--;
    }
  }
  bool clear() {
    while (_end > _begin) {
      alloc.destroy(_end);
      _end--;
    }
  }

  iterator erase(iterator b, iterator e) {
    if (e > _end || b < _begin) {
      throw runtime_error("out of range");
    }
    iterator new_end = copy(e, _end, b);
    while (new_end < _end) {
      alloc.destroy(_end);
      _end--;
    }
    return _end;
  }
  T &operator[](int i) { return *(_begin + i); }
  T &operator[](iterator i) { return *(i); }


private:
  void free() {
    if (_begin) {
      for (auto i = _begin; i < _end; i++) {
        alloc.destroy(i);
      }
      alloc.deallocate(_begin, _end - _begin);
    }
  }
  void check_and_expand() {
    if (_end == _cap) {
      unsigned int new_cap = size() ? size() << 1 : 1;
      expand(new_cap);
    }
  }
  void expand(unsigned int new_cap) {
    auto new_begin = alloc.allocate(new_cap);
    auto new_end = uninitialized_copy(make_move_iterator(_begin),
                                      make_move_iterator(_end), new_begin);
    free();
    _begin = new_begin;
    _end = new_end;
    _cap = _begin + new_cap;
    cout << "new_cap:"<< (_cap-_begin)<<endl;
  }
  iterator _begin = nullptr;
  iterator _end = nullptr;
  iterator _cap = nullptr;
  allocator<T> alloc;
};

利用两个队列实现一个栈,以及利用两个栈来实现一个队列

读取和写入文件,并且要知道如何生成随机数

 void selectKItems(int stream[], int n, int k) 
 { 
    int i;  // index for elements in stream[] 
    int reservoir[k]; 
    for (i = 0; i < k; i++) 
        reservoir[i] = stream[i]; 
    srand(time(NULL)); 
    for (; i < n; i++) 
    { 
        int j = rand() % (i+1); 
        if (j < k) 
          reservoir[j] = stream[i]; 
    } 
    printf("Following are k randomly selected items \n"); 
    printArray(reservoir, k);
    } 
每一个数都可以被分解成质数的和。
    int countPrimes(int n) {
        vector<bool> prime(n, true);
        prime[0] = false, prime[1] = false;
        for (int i = 0; i < sqrt(n); ++i) {
            if (prime[i]) {
                for (int j = i*i; j < n; j += i) {
                    prime[j] = false;
                }    
            }    
        }
        return count(prime.begin(), prime.end(), true);
    }
位:bit = num & (1 << x);    num ^= 1 << x; 等
数学:Cnk=n! / k!(n-k)!    Cnk=Cn-1k+Cn-1k-1    Cnk=Cnn-k   Ank=n!/(n-k)!  Ann=n!
http://www.cs.trincoll.edu/~ram/cpsc110/inclass/conversions.html

lru cache

class LRUCache {
public:
    LRUCache(int capacity): capacity(capacity){}
    
    int get(int key) {
        auto find=cache.find(key);
        if(find!=cache.end()){
           lrulist.splice(lrulist.begin(),lrulist,cache[key]); //移到头部
            return cache[key]->second;
        }
        return -1;
    }
    
    void put(int key, int value) {
        auto find=cache.find(key);
        if(find!=cache.end()){
            cache[key]->second=value;
            lrulist.splice(lrulist.begin(),lrulist,cache[key]); //移到头部
        }else{
            if(lrulist.size()==capacity){
                auto key=lrulist.back().first;
                cache.erase(key);
                lrulist.pop_back();
            }
            lrulist.emplace_front(key,value);
            cache[key]=lrulist.begin();
        }
        
        
    }
private:
    list<pair<int,int>> lrulist;
    unordered_map<int,list<pair<int,int>>::iterator> cache;
    int capacity;
};

Ping-pong

class threadpp2 {
public:
  threadpp2(){
  }
  void static pong() {
    while (1) {
      pthread_mutex_lock(&_mt);
      pthread_cond_wait(&pt, &_mt);
      pthread_mutex_unlock(&_mt);
      cout << "pong" << endl;
      pthread_cond_signal(&pt_pong);
      usleep(100);
    }
  }

  void test(){
    auto t1 = new thread(pong);
    int i=0;
    while(i<10){
      cout<<"ping"<<endl;
      pthread_cond_signal(&pt);
      pthread_mutex_lock (&_mt);
      pthread_cond_wait(&pt_pong,&_mt);
      //cout<<"ack"<<endl;
      pthread_mutex_unlock (&_mt);
      usleep(105);
      i++;
    }
    t1->join();
    delete t1;
  }

  static pthread_mutex_t _mt;
  static pthread_cond_t pt;
  static pthread_cond_t pt_pong;
};
pthread_mutex_t threadpp::_mt = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t threadpp::pt = PTHREAD_COND_INITIALIZER;
pthread_cond_t threadpp::pt_pong= PTHREAD_COND_INITIALIZER;

广度优先搜索(breadth-first-search)、深度优先搜索(depth-first-search),以及中序遍历、后序遍历和前序遍历之间的差别。
堆总能找到最大值,但代价就是寻找其他任何一个值所需的时间都是O(n)。插入和删除所需的时间依然是O(logn)
BFS用queue,dfs在另一个笔记里有很多例子。

后序遍历

vector<int> postorderTraversal(TreeNode* root) {
       //左右根
        //root入栈,若左入栈,没有弹出,当前有右,右入栈,   继续,右侧弹出左孩子后若右也弹出,继续弹出父节点
        vector<int> res;
        if(!root){
            return res;
        }
        stack<TreeNode*> st;
        TreeNode* pre=nullptr;
        while(root||!st.empty()){
            while(root){
                st.push(root);
                root=root->left;
            }
            auto top=st.top();
            if(top->right&&pre!=top->right){
               root=top->right;
            }else{
                res.push_back(top->val);
                st.pop();
                pre=top;
            }
        }
        return res;
    }

字典树

class Trie {
public:
    Trie() {}
    void insert(string word) {
        auto trie=this;
        for(int i=0;i<word.size();i++){
            if(!trie->childs[word[i]-'a']){
                trie->childs[word[i]-'a']=new Trie();
            }
            trie=trie->childs[word[i]-'a'];
        }
        trie->isLeaf=true;
    }
    bool search(string word) {
        auto trie=this;
        for(int i=0;i<word.size();i++){
            if(!trie->childs[word[i]-'a']){
                return false;
            }
            trie=trie->childs[word[i]-'a'];
        }
        return trie->isLeaf;
    }
 
    Trie* childs[26]{};
    bool isLeaf=false;
};

最近祖先

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root||root==p||root==q) return root;
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);
        if(left&&right) return root;
        if(left) return left;
        if(right) return right;
        return nullptr;
    }

二叉树-》二叉搜索树=》平衡树/红黑树 查找、插入和删除就可以在O(log n)

dfs,bfs,回溯

题目有解空间,选了一个不能选另一个,不仅递归,还需要知晓路径,基本都是要使用DFS解题。如果解中含有大量重复,那么此时考虑:能不能从底向上去解题,如果可以,说明此题可以动态规划来解,如果不可以,那么可以使用记忆化搜索:把计算过的值存下来。

是否需要回溯:一个点是否要被访问多次,灌水性质的题目例如:求岛屿个数、二维矩阵迷宫路径、给地图上色;(从一个点灌水,那么他连通的点也会有)
dfs找特殊路径的题目,例如路径长度被限制,或者最长、最短,实际上还是找全部路径,然后在里面挑一个最合适的,也就是说,往往是非灌水性质的。

非回溯dfs,访问过的不需要再访问,就不需要打标回去

int numIslands(vector<vector<char>>& grid) {
        int sum=0;
        for(int i=0;i<grid.size();i++){
            for(int j=0;j<grid[i].size();j++){
                if(grid[i][j]=='1'){
                    sum++;
                    dfs(grid,i,j);
                }
            }
        }
        return sum;
    }
    
    void dfs(vector<vector<char>>& grid,int i,int j){
        if(grid[i][j]=='0') return;
        grid[i][j]='0';
        if(i+1 < grid.size()) dfs(grid,i+1,j);
        if(i > 0) dfs(grid,i-1,j);
        if(j > 0) dfs(grid,i,j-1);
        if(j+1 < grid[i].size()) dfs(grid,i,j+1);
    }

回溯组合dfs

vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> singleres;
        subsets0(nums,singleres,res,0);
        return res;
    } 
       void subsets0(const vector<int>& nums,vector<int>& singleres,vector<vector<int>>& res,int begin) {
        res.push_back(singleres);
        for(int i=begin;i<nums.size();i++){
            singleres.push_back(nums[i]);
            subsets0(nums,singleres,res,i+1);
            singleres.pop_back();
        }
    }
   class Solution {
    public:
    vector<string> digitsvec{"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> letterCombinations(string digits) {
        vector<string> res;
        if(digits.empty()) return res;
        string singleres;
        letterCombinations0(digits,res,singleres,0);
        return res;
    }
    
    void letterCombinations0(const string& digits,vector<string>& res,string& singleres,int deep){
        if(deep==digits.size()){
            res.push_back(singleres);
            return;
        }
        string singlecd=digitsvec[digits[deep]-'2'];
        for(int i=0;i<singlecd.size();i++){
            singleres += singlecd[i];
            letterCombinations0(digits,res,singleres,deep+1);
            singleres.pop_back();
        }
    }
    };
    

回溯排列

    class Solution {
    public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        if(nums.empty()) return res;
        permute0(nums,res,0);
        return res;
    }
    
    void permute0(vector<int>& nums,vector<vector<int>>& res,int begin){
        if(begin==nums.size()){
            res.push_back(nums);
            return;
        }
        for(int i=begin;i<nums.size();i++){
            swap(nums[i],nums[begin]);
            permute0(nums,res,begin+1);
            swap(nums[i],nums[begin]);
        }
    }
    };

n皇后回溯

  int totalNQueens(int n) {
    vector<bool> col(n, true);
    vector<bool> anti(2*n-1, true);
    vector<bool> main(2*n-1, true);
    int res=0;
    queen(col,main,anti,0,res);
    return res;
  }

  bool queen(vector<bool> &col, vector<bool>& main, vector<bool> &anti,int level,int& res){  //按照i,层不需要判断了
    int n=col.size();
    if(level==n) {res++;return true;}
    for(int j=0;j<n;j++){
        if(col[j] && main[level+j] && anti[level+n-1-j]){   //合法
            col[j] = main[level+j] = anti[level+n-1-j] = false;
            queen(col,main,anti,level+1,res);
            col[j] = main[level+j] = anti[level+n-1-j] = true;
         }
    }
    return false;
  }

对于走通的路径很多的情况下,也就是说解很多的时候,使用bfs和dfs是等价的,但是对于解少的情况来说,使用bfs更好。这也是为什么图中求最短路径都是使用BFS

双向词典中最短路径问题

注意虽然头尾是两个队列,但实际上相当于一个队列一个处理的。

int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string> dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail;
        if (dict.find(endWord) == dict.end()) {
            return 0;
        }
        head.insert(beginWord);
        tail.insert(endWord);
        int ladder = 2;
        while (!head.empty() && !tail.empty()) {
            if (head.size() < tail.size()) {
                phead = &head;
                ptail = &tail;
            } else {
                phead = &tail;
                ptail = &head;
            }
            unordered_set<string> temp;
            for (auto it = phead -> begin(); it != phead -> end(); it++) {    
                string word = *it;
                for (int i = 0; i < word.size(); i++) {
                    char t = word[i];
                    for (int j = 0; j < 26; j++) {
                        word[i] = 'a' + j;
                        if (ptail -> find(word) != ptail -> end()) {
                            return ladder;
                        }
                        if (dict.find(word) != dict.end()) {
                            temp.insert(word);
                            dict.erase(word);
                        }
                    }
                    word[i] = t;
                }
            }
            ladder++;
            phead -> swap(temp);
        }
        return 0;
    }

dfs,bfs,拓扑(不关心是否cycle只需要一个visited),iscycle(需要一个visited是否判定无环)

课表是否能完成dfs环路判定

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {        
        vector<int> visited(numCourses,0);
        vector<vector<int>> graphs(numCourses,vector<int>());
        for(auto pre:prerequisites){
            graphs[pre[0]].push_back(pre[1]);
        }
        for(int i=0;i<numCourses;i++){
            if(!dfs(i,visited,graphs)){
                return false;
            }
        }
        return true;
    }
    
    
    bool dfs(int begin,vector<int>& visited,const vector<vector<int>>& graphs){
        if(visited[begin]==2){
            return true;
        }
        if(visited[begin]==1){
            return false;
        }
        visited[begin]=1;
        for(int i=0;i<graphs[begin].size();i++){
            if(!dfs(graphs[begin][i],visited,graphs)){
                return false;
            }
        }
        visited[begin]=2;
        return true;
    }
};

相交集环路

int find(int parent[], int i)  
{  
    if (parent[i] == -1)  
        return i;  
    return find(parent, parent[i]);  
}  
  
void Union(int parent[], int x, int y)  
{  
    int xset = find(parent, x);  
    int yset = find(parent, y);  
    if(xset != yset) 
    {  
        parent[xset] = yset;  
    }  
}  
   
int isCycle( Graph* graph )  
{  
    int *parent = new int[graph->V * sizeof(int)];  
    memset(parent, -1, sizeof(int) * graph->V);  
    for(int i = 0; i < graph->E; ++i)  
    {  
        int x = find(parent, graph->edge[i].src);  
        int y = find(parent, graph->edge[i].dest);  
  
        if (x == y)  
            return 1;  
  
        Union(parent, x, y);  
    }  
    return 0;  
}      

单最短路径

链表

链表深拷贝
next和random两个不同指针的拷贝

    //把2插入到1中,
    //l1->next->random = l1->random->next
    RandomListNode *copyRandomList(RandomListNode *head) {
        RandomListNode *newHead, *l1, *l2;
        if (head == NULL) return NULL;
        for (l1 = head; l1 != NULL; l1 = l1->next->next) {
            l2 = new RandomListNode(l1->label);
            l2->next = l1->next;
            l1->next = l2;
        }
            
        newHead = head->next;
        for (l1 = head; l1 != NULL; l1 = l1->next->next) {
            if (l1->random != NULL) l1->next->random = l1->random->next;
        }
            
        for (l1 = head; l1 != NULL; l1 = l1->next) {
            l2 = l1->next;
            l1->next = l2->next;
            if (l2->next != NULL) l2->next = l2->next->next;
        }
    
        return newHead;
    }
    
    //用map把新旧映射后,random对应下
    public RandomListNode copyRandomList(RandomListNode head) {
        if (head == null) return head;
        RandomListNode newHead = new RandomListNode(head.label);
        RandomListNode oldp = head.next;
        RandomListNode newp = newHead;
        Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
        //采用map结构来存储对应的关系
        map.put(newp, head);
        while (oldp != null) {//复制旧的链表
            RandomListNode newTemp = new RandomListNode(oldp.label);
            map.put(newTemp, oldp);
            newp.next = newTemp;
            newp=newp.next;
            oldp=oldp.next;
        }
        oldp=head;
        newp=newHead;
        while (newp!=null){//复制random指针
            newp.random=map.get(newp).random;//取得旧节点的random指针
            newp=newp.next;
            oldp=oldp.next;
        }
        return head;
    }
链表翻转
    ListNode* reverseList(ListNode* head) {
        ListNode* cur = NULL;
        while (head) {
            ListNode* next = head -> next;
            head -> next = cur;
            cur = head;
            head = next;
        }
        return cur;
    }

    ListNode* reverseList(ListNode* head) {
        if (!head || !(head -> next)) {
            return head;
        }
        ListNode* node = reverseList(head -> next);
        head -> next -> next = head;
        head -> next = NULL;
        return node;
    }
链表去重。要用删除后面节点。head不需要处理

动态规划

最少硬币数

 int coinChange(vector<int>& coins, int n) {
        vector<int> dp(n+1,INT_MAX);
        dp[0] = 0;
        sort(begin(coins), end(coins));
        for (int i = 1; i <= n; i++) {
        
            dp[i] = INT_MAX;
            for (int c: coins) {
                if (i - c < 0) break; //sorted
                if (dp[i - c] != INT_MAX) dp[i] = min(dp[i], 1 + dp[i - c]);
            }
        }
        return dp[n] == INT_MAX ? -1 : dp[n];
    }

最长公共子序列

  int longestCommonSubsequence(string text1, string text2) {
      int len1=text1.size();
      int len2=text2.size();
      if(len1==0||len2==0) return 0;
      vector<vector<int>> dp(len1,vector<int>(len2,0));
      for(int i=0;i<len1;i++){
          for(int j=0;j<len2;j++){
              if(i==0&&j==0) dp[i][j]=text1[i]==text2[j]?1:0;
              else if(i==0) dp[i][j]=text1[i]==text2[j]?1:dp[i][j-1];
              else if(j==0) dp[i][j]=text1[i]==text2[j]?1:dp[i-1][j];
              else dp[i][j]=text1[i]==text2[j]?dp[i-1][j-1]+1:max(dp[i-1][j],dp[i][j-1]);
          }
      }
      return dp[len1-1][len2-1];
  }

斐波那锲

    int climbStairs(int n) {
        if(n<3) return n;
        int f1=1,f2=2,f3;
        for(int i=3;i<=n;i++){
            f3=f1+f2;
            f1=f2;
            f2=f3;
        }
        return f3;
    }

棋盘路径

int uniquePaths(int m, int n) {
        //f[i,j]=f[i-1,j]+f[i,j-1]
        vector<vector<int>> path(m,vector<int>(n));
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i==0||j==0){
                    path[i][j]=1;
                }else{
                    path[i][j] = path[i-1][j]+path[i][j-1];
                }
            }
        }
        return path[m-1][n-1];
    }

背包,限定候选集s/容量cap 下选择最大value

限定 s:01字典,cap:共m个0,n个1, 选择最多个数

int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> DP(m+1,vector<int>(n+1,0));
        for(auto s:strs){
            int cost0=0,cost1=0;
            getZoreOneNums(s,cost0,cost1);
            zoreOnePack(DP,cost0,cost1,1);
        }
        return DP[m][n];
    }
    void zoreOnePack(vector<vector<int>>& DP,int cost0,int cost1,int value){
        for(int i=DP.size()-1;i>=cost0;i--){
            for(int j=DP[0].size()-1;j>=cost1;j--){
                DP[i][j]=max(DP[i][j],DP[i-cost0][j-cost1]+value);
            }
        }
    }

s:整数数组,cap:一半和,value:是否有

bool canPartition(vector<int>& nums) {
//组成容量为sum/2的,是否有,初始无,有则有任一value,不关心最大
        int sum = accumulate(nums.begin(), nums.end(), 0); 
        if(sum%2) return false;
        sum/=2;
        vector<int> DP(sum+1,INT_MIN);
        DP[0]=0;
        for(auto num:nums){
            zoreOnePack(DP,num,0);
        }
        return DP[sum]==INT_MIN?false:true;
    }
    void zoreOnePack(vector<int>& DP,int cost,int value){
        for(int i=DP.size()-1;i>=cost;i--){
            DP[i]=max(DP[i],DP[i-cost]+value);
        }
    }

石头碰撞 s:整数数组,cap:一半和,value:和最大

int lastStoneWeightII(vector<int>& stones) {
        //转化为xi+xj+... - xk-xl-xm-xn-...  个数不一定一样,但是差最小就行
        int sum=accumulate(stones.begin(),stones.end(),0); //cap:sum/2,cost:val, val:val
        int cap = sum/2;
        vector<int> DP(cap+1,0);
        for(auto st:stones){
            zoreOnePack(DP,st,st);
        }
        return sum-DP[cap]*2;
    }
    void zoreOnePack(vector<int>& DP,int cost,int val){
        for(int i=DP.size()-1;i>=cost;i--) {
            DP[i]=max(DP[i],DP[i-cost]+val);
        }
    }

二分查找

寻找两个有序整数数组的中位数

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int len1 = nums1.size();
        int len2 = nums2.size();
        if (len1 > len2) {
          swap(len1, len2);
          swap(nums1, nums2);
        }
        if(len2==0){
            return 0;
        }
        int b1 = 0, e1 = len1, i=0, j=0;
        while (true) {
          i = b1 + (e1 - b1) / 2;      // a[0]...a[i-1] | a[i]...a[len1-1]
          j = (len1 + len2) / 2 - i;  // b[0]...b[j-1] | b[j]...b[len2-1]

          if (i>0 && nums1[i - 1] > nums2[j]) {
            e1 = i - 1;
          } else if (i<len1 && nums2[j - 1] > nums1[i]) {
            b1 = i + 1;
          }else if(i == 0 || i == len1 ||
              (nums1[i - 1] <= nums2[j] && nums2[j - 1] <= nums1[i])) {
            break;
          }
        }
        int left_max,right_min;
        if ((len1 + len2) % 2) {
          if(i==len1) return nums2[j];
          if(j==len2) return nums1[i];
          return min(nums1[i],nums2[j]);
        } else{
            if(j==0) return (nums1[i-1]+nums2[j])/2.0;
            if(j==len2) return (nums2[j-1]+nums1[i])/2.0;
            left_max= (i==0)? nums2[j-1] : max(nums1[i-1],nums2[j-1]);
            right_min= (i==len1) ? nums2[j]:min(nums1[i],nums2[j]);
            return (left_max+right_min)/2.0;
        }
        return -1;
  }

一个数组先升后降,求最大值

    int peakIndexInMountainArray(vector<int>& A) {
        return peakIndexInMountainArray0(A,0,A.size()-1);
    }
    int peakIndexInMountainArray0(const vector<int>& A,int i,int j){
        if(j==i) return i;
        if(j-i==1) return A[i]>A[j]?i:j;
        //3个以上
        int mid=i+(j-i)/2;   
        if(A[mid]>A[mid-1]&&A[mid]>A[mid+1]) return mid;
        if(A[mid]>A[mid-1]&&A[mid]<A[mid+1]) return peakIndexInMountainArray0(A,mid+1,j);
        if(A[mid]<A[mid-1]&&A[mid]>A[mid+1]) return peakIndexInMountainArray0(A,i,mid-1);
        return -1;
    }

单调栈/队列等

数组注意原地。单调栈解决下一个最大问题

最大矩形

    int largestRectangleArea(vector<int>& heights) {
        stack<int> indexes;
        int maxArea = 0;
        heights.push_back(0);  //这里~~统一了,栈里存下标,差值即为宽度,每次遇到右侧小的左侧可以pop计算了,留下的都是比他小的,左右宽度可知。
        indexes.push(0);
        for (int i = 1; i < heights.size(); i++){
            while(!indexes.empty() && heights[i] < heights[indexes.top()]){
                int h = heights[indexes.top()];
                indexes.pop();
                int prev = indexes.empty() ? -1 : indexes.top();
                maxArea = max(maxArea, (i - prev -1) * h);
            }
            indexes.push(i);
        }
        return maxArea;
        
    }

流中位数

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    
    void addNum(int num) {
        int left_size = left_max.size();
        int right_size = right_min.size();
        if(left_size==0 || num<=left_max.top()){
            left_max.push(num);
            if(left_size+1>right_size+1){
                right_min.push(left_max.top());
                left_max.pop();
            }
        }else{
            right_min.push(num);
            if(right_size+1>left_size){
                left_max.push(right_min.top());
                right_min.pop();
            }
        }
    }
    
    double findMedian() {
        if(left_max.empty()){
            return 0;
        }
        if(left_max.size()==right_min.size()){
            return (left_max.top()+right_min.top())/2.0;
        }
        return left_max.top();
    }
    
private:
    priority_queue <int,vector<int>,less<int> > left_max;
    priority_queue <int,vector<int>,greater<int> > right_min;

};

滑动窗口最值

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
       deque<int> dq;
        vector<int> ans;
        for (int i=0; i<nums.size(); i++) {
            if (!dq.empty() && dq.front() == i-k) dq.pop_front();
            while (!dq.empty() && nums[dq.back()] < nums[i])
                dq.pop_back();
            dq.push_back(i);
            if (i>=k-1) ans.push_back(nums[dq.front()]);
        }
        return ans;
    }

滑动窗口中位数

因为一定要删掉上一次的,顺序不定在哪里,所以不能用优先队列了

vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        
        multiset<long> maxset(nums.begin(),nums.begin()+k);
        auto mid = next(maxset.begin(),k/2);
        vector<double> res;
        for(int i=0;i+k<nums.size();i++){
            if(k%2){
                res.push_back(*mid);
            }else{
                auto pre = prev(mid,1);
                res.push_back((*mid+*pre)/2.0);
            }
            maxset.insert(nums[i+k]);
            if(nums[i+k]<*mid) mid--;
            if(nums[i]<=*mid) mid++;
            maxset.erase(maxset.lower_bound(nums[i]));
        }
        if(k%2){
            res.push_back(*mid);
        }else{
            auto pre = prev(mid,1);
            res.push_back((*mid+*pre)/2.0);
        }
        return res;
    }

比较函数写法

auto cmp = [](pair<string,int>& a,pair<string,int>&b){
                return a.second>b.second || (a.second==b.second&&a.first<b.first);
            };
    vector<string> res;
    priority_queue<pair<string,int>,vector<pair<string,int>>,decltype(cmp)> mq(cmp);
    
     struct cmp{
        bool operator()(const pair<string,int>& a, const pair<string,int>& b) const {
            return a.second>b.second || (a.second==b.second&&a.first<b.first);
        }
    };
    priority_queue<pair<string,int>,vector<pair<string,int>>,cmp> mq;

    priority_queue <int,vector<int>,less<int> > left_max;  //大根堆
    priority_queue <int,vector<int>,greater<int> > right_min;  //小根堆

    struct _LIBCPP_TEMPLATE_VIS less : binary_function<_Tp, _Tp, bool>
    {
        bool operator()(const _Tp& __x, const _Tp& __y) const
        {return __x < __y;}
    };
    
    struct _LIBCPP_TEMPLATE_VIS greater : binary_function<_Tp, _Tp, bool>
    {
        bool operator()(const _Tp& __x, const _Tp& __y) const
        {return __x > __y;}
    };
可重复和
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ret;
        vector<int> sret;
        sort(candidates.begin(),candidates.end());
        combinationSumInner(candidates,0,target,sret,ret);
        return ret;
    }

    void combinationSumInner(vector<int>& candidates,int begin,int target,vector<int>& sret,vector<vector<int>>& ret){
        for(int i=begin;i<candidates.size();i++){
            if(target-candidates[i]>0){
                sret.push_back(candidates[i]);
                combinationSumInner(candidates,i,target-candidates[i],sret,ret);
                sret.erase(sret.end()-1);
            }else if(target-candidates[i]==0){
                sret.push_back(candidates[i]);
                ret.push_back(sret);
                sret.erase(sret.end()-1);
            }
        }
    }
    
    不可重复和
    void combinationSumInner(vector<int>& candidates,int begin,int target,vector<int>& sret,vector<vector<int>>& ret){
        for(int i=begin;i<candidates.size();i++){
            if(i>begin && candidates[i]==candidates[i-1]) continue;   //去重复
            if(target-candidates[i]>0&&(i<candidates.size()-1)){
                sret.push_back(candidates[i]);
                combinationSumInner(candidates,i+1,target-candidates[i],sret,ret);   //前移
                sret.erase(sret.end()-1);
            }else if(target-candidates[i]==0){
                sret.push_back(candidates[i]);
                ret.push_back(sret);
                sret.erase(sret.end()-1);
            }
        }
    }

    数字加和
     void combinationSumInner(int k,int begin,int n,vector<int>& sret,vector<vector<int>>& ret){
        for(int i=begin;i<10;i++){
            if(n-i>0&&(i<9)&&k>1){
                sret.push_back(i);
                combinationSumInner(k-1,i+1,n-i,sret,ret);   //前移
                sret.erase(sret.end()-1);
            }else if(n-i==0&&k==1){
                sret.push_back(i);
                ret.push_back(sret);
                sret.erase(sret.end()-1);
            }
        }
    }
k-sum问题
转为一个和和k-1sum的问题。常规复杂度n^(k-1)
2-sum 首尾指针。或者一个hash 另一个查加和
3-sum 一个for 两个首尾。只要后面的
4-sum 2个先缓存,再用2-sum的chahe

梦想家
107 声望76 粉丝