基础
二分查找
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。