算法学习笔记,本篇主要是一些基本的知识整理
Leetcode高频算法实战学习·
一、数组·
数组理论·
使用静态数组实现的方法:每次大小不够时将新的静态数组长度增大一倍 ,这样就可以将拷贝数值的复杂度降到$O(n)$
不同遍历方式差别很大,以下三种从上到下时间依次上升。
参考博客:https://blog.csdn.net/xiewuquan/article/details/50492096
1 2 3 4 5 6 7 8 9 10 vector <int > a;for (int i=0 ;i<a.size ();i++){ print (a[i]); } for (int x:a){ print (x); } for (vector <int >::iterator it:a.begin ();it!=a.end ();it++){ print (it); }
emplace_back
效果和push_back
一致,最好使用前者,节省空间开销
如果已经确定了数组长度,就直接先使用vector<int> ans(n);
初始化好再直接用下标索引直接赋值,比一个个push_back
快
扫描数组技巧·
求数组区间和,区间方差,二位数组矩阵区域和方法:记录从0到每个序号的和,然后用sum[j]-sum[i-1]的方式求出区间[i,j]的和
序列问题·
下一个排列·
数组长度小于2直接返回原数组
从后往前扫描找到一个序号i使得nums[i]<nums[i+1]
在nums[i+1,n-1]之间找到一个大于nums[i]且最小的数的序号mini,将mini和i处的数交换
将i位置之后的数组逆序(由从大到小变为从小到大)
前一个排列·
数组长度小于2直接返回原数组
从后往前扫描找到一个序号i使得nums[i]>nums[i+1]
在nums[i+1,n-1]之间找到一个小于nums[i]且最大的数的序号maxi,将maxi和i处的数交换
将i位置之后的数组逆序(由从小到大变为从大到小)
逆序过程可以用sort函数
1 2 3 4 5 sort(nums+i,nums+n-1 ,cmp); sort(nums.begin ()+i,nums.end (),cmp); static bool cmp (const int a,const int b) { return a>b; }
最大子序和·
最大连续子数组和·
先求出从0
到每个位置的和,用sums
记录,在这个遍历过程中同时记录在每个位置之前的位置中sum最小的位置,也用另一个数组存储。
之后对每个位置i
,计算sums[i]-sums[minPos[i]]
的最大值
环形数组最大连续子数组和·
用一个普通数组表示环形数组
分为两种情况
case1:最大的子数组在原数组中间,此时等价于之前普通的数组情况
case2:最大子数组在原数组两边,此时等价于求最小连续子数组和
有序数组查找问题·
两数之和·
有序数组中,两个指针l,r记录。两个位置数字和与目标值比较,一样的话返回,大了就r–,小的话就l++。
三数之和·
三个指针i j k(i<=j<=k)
定死一个位置i,看是否存在nums[j]+nums[k]=target-nums[i]
二分查找·
1 2 3 4 5 6 7 8 9 10 11 12 13 int n=nums.size ();int l=0 ,r=n-1 ;while (l<=r){ int mid=(l+r)/2 ; if (nums[mid]==target){ return mid; } else if (nums[mid]<target){ l=mid+1 ; } else { r=mid-1 ; } } return -1 ;
搜索旋转排序矩阵·
类似二分查找的思路,加一些判定
假设左边的数位置是 L,右边位置是 R:
如果当前数组的长度小于等于 2 的话,我们按边界条件处理。
否则,取中间的位置 M,先判断目标值和 M 位置值的关系,如果相等直接返回 M。
然后,如果 M 位置的值大于 L 位置的值:
如果 M 位置的值小于 L 位置的值:
如果目标值在 M 到 R 之间,递归右边部分。
其他情况,递归左边部分。
搜索二维矩阵·
每次从左下角的指针开始判断
对于m*n矩阵,初始化指针为x=m-1,y=0
之后nums[x][y]>target
就x–
相等就返回
小于就y++
二、栈·
后进先出
需要实现top() size() pop() push(x)四个操作
括号匹配·
表达式计算·
三、队列·
先进先出
滑动窗口最大值·
方法2:使用单调双向队列解决问题·
原理:如果在k个数中存在一个编号i<j
,nums[i]<=nums[j]
则nums[i]
必定不可能是最大的那个数,因此将这样的数出队。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution {public : vector <int > maxSlidingWindow (vector <int >& nums, int k) { deque <int > q; int n=nums.size (); for (int i=0 ;i<k;i++){ while (!q.empty()&&nums[q.back()]<=nums[i]){ q.pop_back(); } q.push_back(i); } vector <int > ans={nums[q.front()]}; for (int i=k;i<n;i++){ while (!q.empty()&&nums[q.back()]<=nums[i]){ q.pop_back(); } q.push_back(i); if (q.front()<i-k+1 ){ q.pop_front(); } ans.push_back(nums[q.front()]); } return ans; } };
方差计算:$D(x)=\sum x_i^2-((\sum x_i)/n)^2$
求岛屿最大面积·
遍历每一个土地,是1则开始广度搜索,同时将搜索到的土地标记为0,即不能再次访问,直到队列为空。
四、链表·
反转链表·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ListNode* recurseWay (ListNode* head) { if (!head||!head->next){ return head; } ListNode * newHead=recurseWay(head->next); head->next->next=head; head->next=nullptr ; return newHead; } ListNode* noRecurseWay (ListNode* head) { ListNode* newHead=nullptr ; while (head){ ListNode* nt=head->next; head->next=newHead; newHead=head; head=nt; } return newHead; }
五、树·
前序遍历:根节点–>左子树–>右子树
中序遍历:左子树–>根节点–>右子树
后序遍历:左子树–>右子树–>根节点
根据前序遍历和中序遍历结果构造二叉树·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode() : val(0 ), left(nullptr ), right(nullptr ) {} TreeNode(int x) : val(x), left(nullptr ), right(nullptr ) {} TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} }; class mySolution {public : TreeNode* buildTree (vector <int >& preorder, vector <int >& inorder) { if (preorder.empty()){ return nullptr ; } int rootval=preorder[0 ]; int n=inorder.size (); TreeNode* root=new TreeNode(rootval); int r=find (inorder.begin (),inorder.end (),rootval)-inorder.begin (); vector <int > preorder1; vector <int > preorder2; vector <int > inorder1; vector <int > inorder2; for (int i=0 ;i<r;i++){ preorder1.push_back(preorder[1 +i]); inorder1.push_back(inorder[i]); } for (int i=r+1 ;i<n;i++){ preorder2.push_back(preorder[i]); inorder2.push_back(inorder[i]); } root->left=buildTree(preorder1,inorder1); root->right=buildTree(preorder2,inorder2); return root; } }; class officalSolution {private : unordered_map <int ,int > index; public : TreeNode* buildTree (vector <int >& preorder, vector <int >& inorder) { int n=inorder.size (); for (int i=0 ;i<n;i++){ index[inorder[i]]=i; } return myBuildTree(preorder,inorder,0 ,n-1 ,0 ,n-1 ); } TreeNode* myBuildTree (vector <int >& preorder,vector <int >& inorder,int prel,int prer,int inl,int inr) { if (prel>prer){ return nullptr ; } TreeNode* root=new TreeNode(preorder[prel]); int rooti=index[preorder[prel]]; int leftLen=rooti-inl; root->left=myBuildTree(preorder,inorder,prel+1 ,prel+leftLen,inl,inl+leftLen-1 ); root->right=myBuildTree(preorder,inorder,prel+leftLen+1 ,prer,rooti+1 ,inr); return root; } };
根据中序和后序遍历结果构造也是同理,只需要对上述做法微调即可。
层序遍历·
普通递归或者BFS都可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Solution {private : vector <vector <int >> ans; public : vector <vector <int >> levelOrder (TreeNode* root) { dfsLevelOrder(root,1 ); return ans; } void myLevelOrder (TreeNode* root,int level) { if (root!=nullptr ){ if (level>ans.size ()){ vector <int > ls; ls.push_back(root->val); ans.push_back(ls); } else { ans[level-1 ].push_back(root->val); } myLevelOrder(root->left,level+1 ); myLevelOrder(root->right,level+1 ); } } vector <vector <int >> bfsLevelOrder (TreeNode* root) { vector <vector <int >> ret; if (!root) { return ret; } queue <TreeNode*> q; q.push(root); while (!q.empty()) { int currentLevelSize = q.size (); ret.push_back(vector <int > ()); for (int i = 1 ; i <= currentLevelSize; ++i) { auto node = q.front(); q.pop(); ret.back().push_back(node->val); if (node->left) q.push(node->left); if (node->right) q.push(node->right); } } return ret; } };
寻找最近公共祖先·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : TreeNode* lowestCommonAncestor (TreeNode* root, TreeNode* p, TreeNode* q) { if (root==p||root==q){ return root; } TreeNode* ansl=nullptr ; TreeNode* ansr=nullptr ; if (root->left!=nullptr ){ ansl=lowestCommonAncestor(root->left,p,q); } if (root->right!=nullptr ){ ansr=lowestCommonAncestor(root->right,p,q); } if (ansl!=nullptr &&ansr!=nullptr ){ return root; } else if (ansl!=nullptr ){ return ansl; } else { return ansr; } } };
树上最接近的两部分·
删除一条边使得分开的两部分节点之和最接近(差的绝对值最小)
思路:先求出每个子树的和并记录在对应节点的val中,再遍历每个节点找出答案
最优子结构特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution {public : int similarTwoParts (TreeNode* root) { getSum(root); int s=root->val; int minsum=0x3fffff ; findMax(root,minsum,s); return minsum; } void findMax (TreeNode* root,int &minsum,int rootsum) { if (root==nullptr ){ return ; } if (root->val!=rootsum&&abs (rootsum-2 *root->val)<minsum){ minsum=abs (rootsum-2 *root->val); } findMax(root->left,minsum,rootsum); findMax(root->right,minsum,rootsum); } int getSum (TreeNode* root) { if (root==nullptr ){ return 0 ; } root->val=getSum(root->left)+getSum(root->right)+root->val; return root->val; } };
六、堆(优先队列)·
堆:完全二叉树,且每个子树的根节点的值都是这个子树的最大值或者最小值
判断二叉树是否为堆·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution {private : vector <int > index; public : bool isLegalHeap (TreeNode* root) { getIndex(root,0 ); sort(index.begin (),index.end ()); for (int i=1 ;i<index.size ();i++){ if (index[i]>index[i-1 ]+1 ){ return false ; } } return isBiggestLegalHeap(root)||isLeastLegalHeap(root); } void getIndex (TreeNode* root,int i) { if (root==nullptr ){ return ; } index.push_back(i); getIndex(root->left,i*2 +1 ); getIndex(root->right,i*2 +2 ); } bool isBiggestLegalHeap (TreeNode* root) { if (root==nullptr ){ return true ; } if (root->left!=nullptr &&root->left->val>root->val||root->right!=nullptr &&root->right->val>root->val){ return false ; } return isBiggestLegalHeap(root->left)&&isBiggestLegalHeap(root->right); } bool isLeastLegalHeap (TreeNode* root) { if (root==nullptr ){ return true ; } if (root->left!=nullptr &&root->left->val<root->val||root->right!=nullptr &&root->right->val<root->val){ return false ; } return isLeastLegalHeap(root->left)&&isLeastLegalHeap(root->right); } };
将二叉树转换为堆·
改进的BFS层序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : vector <int > transferHeapToList (TreeNode* root) { vector <int > heap; queue <TreeNode*> q; q.push(root); while (!q.empty()){ int sz=q.size (); for (int i=0 ;i<sz;i++){ TreeNode* node=q.front();q.pop(); heap.push_back(node->val); if (node->left!=nullptr ){ q.push(node->left); } if (node->right!=nullptr ){ q.push(node->right); } } } return heap; } };
合并k个有序链表 ※※※·
维护这k个有序链表的头节点的优先队列(即最小堆),每次从最小堆里弹出最小的节点并将他的链表后继节点加入堆中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public : struct Status { int val; ListNode *ptr; bool operator < (const Status &rhs) const { return val > rhs.val; } }; priority_queue <Status> q; ListNode* mergeKLists (vector <ListNode*>& lists) { for (auto node: lists) { if (node) q.push({node->val, node}); } ListNode head, *tail = &head; while (!q.empty()) { auto f = q.top(); q.pop(); tail->next = f.ptr; tail = tail->next; if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next}); } return head.next; } };
合并k个最小堆·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Solution {public : struct Status { int i; int val; bool operator < (const Status &rhs) const { return val > rhs.val; } }; priority_queue <Status> q; vector <int > mergeKHeaps (vector <vector <int >>& heaps) { vector <int > ans; for (int i=0 ;i<heaps.size ();i++){ q.push({i,heaps[i][0 ]}); } while (!q.empty()){ ans.push_back(extractMin(heaps)); } return ans; } int extractMin (vector <vector <int >>& heaps) { struct Status top =q .top (); q.pop(); int n=heaps[top.i].size (); int tmp=heaps[top.i][n-1 ];heaps[top.i][n-1 ]=heaps[top.i][0 ];heaps[top.i][0 ]=tmp; heaps[top.i].pop_back(); if (!heaps[top.i].empty()){ minHeapify(heaps[top.i],0 ); q.push({top.i,heaps[top.i][0 ]}); } return top.val; } void minHeapify (vector <int >& heap,int i) { int n=heap.size (); int l=i*2 +1 ; int mini=i; if (l<n&&heap[l]<heap[mini]){ mini=l; } int r=i*2 +2 ; if (r<n&&heap[r]<heap[mini]){ mini=r; } if (mini!=i){ int tmp=heap[i];heap[i]=heap[mini];heap[mini]=tmp; minHeapify(heap,mini); } } };
七、二叉查找树·
八、图·
广度优先搜索遍历 DFS
深度优先搜索遍历 BFS
九、设计类问题·
十、贪心与分治·
问题拆解与相应原则 ※※※ ·
如果子问题最优则原问题最优,贪心算法。
如果子问题需要全部求解才能求解原问题,子问题互相独立,分治算法。
如果子问题最优不能保证原问题最优,但是子问题之间不会循环(所谓循环,是指从问题 A 拆解出子问题 B,然后子问题 B 又能拆解出子问题 A),考虑动态规划算法。
更加复杂的情况,我们总是可以考虑暴力搜索解决。
分发饼干·
先将需求数组g和尺寸数组s排序,然后对于每一个孩子的需求都寻找到最小的符合需求的饼干 进行满足
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : int findContentChildren (vector <int >& g, vector <int >& s) { sort(g.begin (),g.end ()); sort(s.begin (),s.end ()); int n=g.size (); int m=s.size (); int i=0 ,j=0 ; for (;i<n&&j<m;i++){ if (s[j]<g[i]){ i--; } j++; } return i; } };
用最少数量的箭引爆气球·
遇到区间类的贪心问题,都先考虑排序,一般按照左端点或者右端点排序,控制复杂度为 $O(n\lg n)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Solution {public : typedef struct node { int point ; int type; int pos; } Node; static bool cmp (Node x,Node y) { return x.point <y.point ?true : x.point >y.point ?false : x.type==0 ?true :false ; } int findMinArrowShots (vector <vector <int >>& points) { vector <Node> nodes; int n=points.size (); vector <int > exist (n,0 ) ; queue <int > targets; int ans=0 ; for (int i=0 ;i<n;i++){ nodes.push_back({points[i][0 ],0 ,i}); nodes.push_back({points[i][1 ],1 ,i}); } sort(nodes.begin (),nodes.end (),cmp); for (auto node:nodes){ if (node.type==0 ){ targets.push(node.pos); } else { if (!exist[node.pos]){ ans++; while (!targets.empty()){ exist[targets.front()]=1 ; targets.pop(); } } } } return ans; } };
快速幂·
例子:$3^{15}$ $15=(1111)_2 $ $3{15}=3 {1+2+4+8}$
分治算法的经典例子
可以延申求矩阵快速幂,用于动态规划的加速
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : double myPow (double x, int n) { long long N=n; return n>=0 ?quickMul_recursion(x,n):1 /quickMul_recursion(x,-N); } double quickMul_recursion (double x,long long n) { if (n==0 ) return 1 ; double y=quickMul_recursion(x,n/2 ); return n%2 ==1 ?y*y*x:y*y; } double quickMul (double x,long long n) { double x_exp=x; double ans=1 ; while (n){ if (n%2 ==1 ) ans*=x_exp; x_exp*=x_exp; n/=2 ; } return ans; } };
排序链表·
$O(n\lg n)$ 时间复杂度与常数空间复杂度情况下完成链表排序
分治算法,先拆分再合并,类似归并排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 class Solution {public : ListNode* sortList (ListNode* head) { ListNode* odd=nullptr ; ListNode* even=nullptr ; ListNode* podd=nullptr ; ListNode* peven=nullptr ; ListNode* p=head; int i=0 ; while (p){ if (i%2 ==0 ) { if (!even) even=p; else peven->next=p; peven=p; } else { if (!odd) odd=p; else podd->next=p; podd=p; } p=p->next; i++; } if (podd) podd->next=nullptr ; if (peven) peven->next=nullptr ; if (i<=1 ) return head; return mergeNode(sortList(even),sortList(odd)); } ListNode* mergeNode (ListNode* p,ListNode* q) { ListNode* ans=nullptr ; ListNode* cur=nullptr ; while (p||q){ if (!q||(p&&(p->val<q->val))){ if (!ans) ans=p; else cur->next=p; cur=p; p=p->next; } else { if (!ans) ans=q; else cur->next=q; cur=q; q=q->next; } } cur->next=nullptr ; return ans; } };
数组中出现次数超过一半的数字·
分治:子问题为在子数组中出现次数超过一半的数,最后将左右两个子数组的结果合并
贪心:摩尔投票,利用抵消的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution {public : int majorityElement (vector <int >& nums) { unordered_map <int ,int > num2cnt; int n=nums.size (); for (int i=0 ;i<n;i++){ num2cnt[nums[i]]++; if (num2cnt[nums[i]]>n/2 ){ return nums[i]; } } return 0 ; } }; class Solution {public : int majorityElement (vector <int >& nums) { int n=nums[0 ]; int cnt=1 ; int m=nums.size (); for (int i=1 ;i<m;i++){ if (nums[i]==n) cnt++; else { if (cnt==0 ){ n=nums[i]; cnt=1 ; } else cnt--; } } return n; } };
十一、常用排序算法·
冒泡排序,归并排序,快速排序,桶排序,堆排序
对角线遍历 II·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution {public : typedef struct node { int s; int y; }Node; static bool cmp (Node x,Node y) { return x.s<y.s?true : x.s>y.s?false : x.y<y.y?true :false ; } vector <int > findDiagonalOrder (vector <vector <int >>& nums) { vector <Node> tmp; vector <int > ans; for (int i=0 ;i<nums.size ();i++){ for (int j=0 ;j<nums[i].size ();j++){ tmp.push_back({i+j,j}); } } sort(tmp.begin (),tmp.end (),cmp); for (auto x:tmp){ ans.push_back(nums[x.s-x.y][x.y]); } return ans; } };
最大间距·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution {public : int maximumGap (vector <int >& nums) { return maximumGap_normal(nums); } int maximumGap_normal (vector <int >& nums) { sort(nums.begin (),nums.end ()); int ans=0 ,n=nums.size (); if (n<2 )return 0 ; for (int i=0 ;i<n-1 ;i++){ ans=max (ans,nums[i+1 ]-nums[i]); } return ans; } int maximumGap_Bucketsort (vector <int >& nums) { int n=nums.size (); if (n<2 )return 0 ; int minx=*min_element(nums.begin (), nums.end ()); int maxx=*max_element(nums.begin (), nums.end ()); if (n==2 )return maxx-minx; int d=ceil ((double )(maxx-minx)/(n-1 )); if (maxx==minx)return 0 ; vector <int > minBuc (n-1 ,maxx+1 ) ; vector <int > maxBuc (n-1 ,minx-1 ) ; vector <bool > ap (n-1 ,false ) ; for (int i=0 ;i<n;i++){ int pos=(nums[i]-minx)/d; if (pos>=n-1 )pos=n-2 ; if (!ap[pos])ap[pos]=true ; if (minBuc[pos]>nums[i])minBuc[pos]=nums[i]; if (maxBuc[pos]<nums[i])maxBuc[pos]=nums[i]; } int ans=d; for (int i=0 ;i<n-1 ;i++){ if (!ap[i])continue ; int j=i+1 ; while (j<n-1 &&!ap[j])j++; if (j==n-1 )break ; ans=max (ans,minBuc[j]-maxBuc[i]); i=j-1 ; } return ans; } };
有效的字母异位词·
判断两个单词的每个字母出现次数是否均一样
采用桶排序,也可以理解为使用标记数组或hash表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : bool isAnagram (string s, string t) { int cnts[26 ]={0 }; int cntt[26 ]={0 }; int n=s.size (); for (int i=0 ;i<n;i++){ cnts[s[i]-'a' ]++; } n=t.size (); for (int i=0 ;i<n;i++){ cntt[t[i]-'a' ]++; } for (int i=0 ;i<26 ;i++){ if (cnts[i]!=cntt[i])return false ; } return true ; } };
十二、Trie 树和KMP 算法·
《labuladong算法小抄》笔记·
一、语言基础·
C++·
传参用&
表示引用
1 2 pair<int,int> p(1,2); cout<<p.first<<p.second;
1.动态数组vector·
https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html
https://www.cnblogs.com/maluning/p/8570717.html
初始化·
1 2 3 4 5 6 7 int n=7 ,m=8 ;vector <int > nums;vector <int > nums (n) ; vector <int > nums{1 ,3 ,5 }; vector <int > nums (n,2 ) ; vector <vector <int >> dp; vector <vector <bool >> dp (m,vector <bool >(n,true )) ;
成员函数·
1 2 3 4 5 6 bool empty () size_type size () ; reference back () ; void push_back (const value_type& val) ; void pop_back () ; erase(vector <int >::iterator);
2.字符串string·
初始化·
1 2 string s; string s="abc" ;
成员函数·
1 2 3 4 5 6 size_t size () ;bool empty () ;void push_back (char c) ; void pop_back () ; string substr (size_t pos,size_t len) ; cout <<s1==s2;
3.哈希表unordered_map·
初始化·
1 2 unordered_map <int ,int > mapping; unordered_map <string ,int > mapping;
成员函数·
1 2 3 4 size_type size () ; bool empty () ;size_type count (const key_type& key) ; size_type erase (const key_type& key) ;
常见操作·
1 2 3 4 5 6 7 8 9 10 vector <int > nums{1 ,2 ,3 ,4 ,5 ,6 }unordered_map <int ,int > counter;for (int num:nums){ counter[num]++; } for (auto & it:counter){ int key=it.first; int value=it.second; cout <<key<<":" <<value<<endl ; }
4.哈希集合unordered_set·
初始化·
1 2 unordered_set <int > visited;unordered_set <string > visited;
成员函数·
1 2 3 4 5 size_type size () ; bool empty () ;size_type count (const key_type& key) ; pair<iterator,bool> insert(const key_type& key);//插入元素 size_type erase (const key_type& key) ;
5.队列queue·
初始化·
1 2 queue <int > q;queue <string > q;
成员函数·
1 2 3 4 5 6 size_type size () ; bool empty () ;void push (const value_type&val) ; value_type& front () ; void pop () ; int e=q.front();q.pop();
5.1双向队列deque·
1 2 3 4 5 void push_back (const value_type&val) ;void pop_back () ;void push_front (const value_type&val) ;void pop_front () ;value_type& front () ;back();
6.堆栈stack·
初始化·
1 2 stack <int > stk;stack <string > stk;
成员函数·
1 2 3 4 5 size_type size () ; bool empty () ;void push (const value_type&val) ; value_type& top () ; void pop () ;
Java·
1.数组·
1 2 3 4 int m=5 ,n=10 ;int [] nums=new int [n];boolean [][] visited=new boolean [m][n];nums.length -->获得数组长度
2.字符串String·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 String s1="Hello,world" ; char c=s1.charAt(2 ); char [] chars=s1.toCharArray(); chars[1 ]='a' ; String s2=new String(chars); System.out.println(s2); if (s1.equals(s2)){ }else { } String s3=s1+"!" ; StringBuilder sb=new StringBuilder(); for (char c='a' ;c<'f' ;c++){ sb.append(c); } sb.append('a' ).append("avx" ).append(1234 ) String s=sb.toString();
3.动态数组ArrayList·
类似C++
的vector
E
代表元素,下同
1 2 3 4 5 6 ArrayList<String> nums=new ArrayList<>(); ArrayList<Integer> strings=new ArrayList<>(); boolean isEmpty () ;int size () ; E get (int index) ; boolean add (E e) ;
4.双链表LinkedList·
1 2 3 4 5 6 7 8 LinkedList<String> strings=new LinkedList<>(); boolean isEmpty () ;int size () ; boolean contains (Object o) ; boolean add (E e) ;boolean addFirst (E e) ; E removeFirst () ;E removeLast () ;
5.哈希表HashMap·
1 2 3 4 5 6 7 8 9 10 11 12 HashMap<Integer,String> map=new HashMap<>(); HashMap<String,int []> map=new HashMap<>(); boolean containsKey (Object key) ; V get (Object key) ;V put (K key,V value) ; V remove (Object key) ; V getOrDefault (Object key,defaultValue) Set<k> keySet () V putIfAbsent (K key,V value) ;
6.哈希集合HashSet·
1 2 3 4 Set<String> set=new HashSet<>(); boolean add (E e) ; boolean contains (Object o) ; boolean remove (Object o) ;
7.队列Queue·
Queue
是一个接口,初始化方式相对特别
1 2 3 4 5 6 7 Queue<String> q=new LinkedList<>(); boolean isEmpty () ;int size () ;E peek () ; E poll () ; boolean offer (E e) ;
8.堆栈Stack·
1 2 3 4 5 6 Stack<integer> s=new Stack<>(); boolean isEmpty () ;int size () ;E push (E e) ;E peek () ; E pop () ;
Python·