算法-基础知识汇总
算法
STL容器(C++)
顺序容器
- 静态的连续数组 array
- 动态的连续数组 vector
- 双端队列 deque
- 单链表 forward_list
- 双链表 list
关联容器
- 唯一键的集合,按照键排序 set
- 键值对的集合,按照键排序,键是唯一的 map
- 键的集合,按照键排序 multiset
- 键值对的集合,按照键排序 multimap
无序关联容器
- 唯一键的集合,按照键生成散列 unordered_set
- 键值对的集合,按照键生成散列,键是唯一的 unordered_map
- 键的集合,按照键生成散列 unordered_multiset
- 键值对的集合,按照键生成散列 unordered_multimap
容器适配器
- 适配一个容器以提供栈(LIFO数据结构) stack
- 适配一个容器以提供队列(FIFO数据结构) queue
- 适配一个容器以提供优先级队列 priority_queue
详细内容
- 顺序容器
array(C++11开始)
template <class T, std::size_t N> struct array;
vector\deque\forward_list\list
template <class T, class Allocator = std::allocator<T> > class vector;
template <class T, class Allocator = std::allocator<T> > class deque;
template <class T, class Allocator = std::allocator<T> > class forward_list;
template <class T, class Allocator = std::allocator<T> > class list;
- 关联容器
set\map\multiset\multimap
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class multiset;
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class multimap;
- 无序关联容器
unordered_set\unordered_map\unordered_multiset\unordered_multimap
template<
class Key,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>
> class unordered_set;
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
template<
class Key,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<Key>
> class unordered_multiset;
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_multimap;
- 容器适配器
stack\queue\priority_queue
template<
class T,
class Container = std::deque<T>
> class stack;
template<
class T,
class Container = std::deque<T>
> class queue;
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
数据结构
二叉树
- 前序遍历
class Solution {
public:
void traverse(TreeNode * root, vector<int> &res) {
if(root==nullptr){
return;
}
res.push_back(root->val);
traverse(root->left, res);
traverse(root->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
traverse(root, res);
return res;
}
};
- 中序遍历
class Solution {
public:
vector<int> result;
void travers(TreeNode *root) {
if(!root) {
return;
}
travers(root->left);
result.push_back(root->val);
travers(root->right);
}
vector<int> inorderTraversal(TreeNode* root) {
travers(root);
return result;
}
};
- 后续遍历
class Solution {
public:
void traverse(TreeNode *root, vector<int> &res){
if(root == nullptr){
return ;
}
traverse(root->left, res);
traverse(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
traverse(root, res);
return res;
}
};
- 分层遍历
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root) return res;
deque<TreeNode *> q;
q.push_back(root);
int nextLine = 0, printLen = 1;
while(!q.empty()){
vector<int> p_res;
while(printLen>0) {
TreeNode *node = q.front();
p_res.push_back(node->val);
printLen--;
if(node->left) {
nextLine++;
q.push_back(node->left);
}
if(node->right) {
nextLine++;
q.push_back(node->right);
}
q.pop_front();
}
swap(printLen, nextLine);
res.emplace_back(p_res);
}
return res;
}
- 判断对称二叉树
class Solution {
public:
bool isSymmetric(TreeNode *root1, TreeNode *root2) {
if(root1 == nullptr && root2 == nullptr){
return true;
} else if(root1 == nullptr || root2 == nullptr){
return false;
}
if(root1->val == root2->val &&
isSymmetric(root1->left, root2->right) &&
isSymmetric(root1->right, root2->left)){
return true;
}
return false;
}
bool isSymmetric(TreeNode* root) {
if(root == nullptr || (root->left == nullptr && root->right == nullptr)){
return true;
}
return isSymmetric(root->left, root->right);
}
};
- 判断平衡树
class Solution {
public:
int depth(TreeNode *root) {
if(root == 0) {
return 0;
}
return 1 + max(depth(root->right), depth(root->left));
}
bool isBalanced(TreeNode* root) {
if(!root) { return true; }
return abs(depth(root->left) - depth(root->right)) <= 1 &&
isBalanced(root->right) && isBalanced(root->left);
}
};
- 分层打印二叉树
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root) return res;
deque<TreeNode *> q;
q.push_back(root);
int nextLine = 0, printLen = 1;
while(!q.empty()){
vector<int> p_res;
while(printLen>0) {
TreeNode *node = q.front();
p_res.push_back(node->val);
printLen--;
if(node->left) {
nextLine++;
q.push_back(node->left);
}
if(node->right) {
nextLine++;
q.push_back(node->right);
}
q.pop_front();
}
swap(printLen, nextLine);
res.emplace_back(p_res);
}
return res;
}
- 二叉树的最大直径
class Solution {
public:
int ans = 0;
int depth(TreeNode *root) {
if(!root) return 0;
int L = depth(root->left);
int R = depth(root->right);
ans = max(L + R, ans);
return 1 + max(L, R);
}
int diameterOfBinaryTree(TreeNode* root) {
if(!root) return 0;
depth(root);
return ans;
}
};
- 验证二叉搜索树
bool isValidBST(TreeNode* root) {
if(!root) return true;
if(!isValidBST(root->left)) {
return false;
}
if(root->val <= pre){
return false;
}
pre = root->val;
return isValidBST(root->right);
}
- 不同的二叉搜索树的组合数
int numTrees(int n) {
vector<int> r(n+1);
r[0] = r[1] = 1;
for(int i=2;i<n+1;i++) {
for(int j=1;j<i+1;j++){
r[i] += r[j-1] * r[i-j];
}
}
return r[n];
}
双指针法 - 链表
- 找到相交链表的重合节点
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(!headA || !headB){
return nullptr;
}
ListNode *pA = headA, *pB = headB;
while(pA != pB) {
pA = pA == nullptr ? headB : pA->next;
pB = pB == nullptr ? headA : pB->next;
}
return pA;
}
- K个一组翻转链表
void reverseRange(ListNode **prev, int k){
if(!prev || !(*prev)->next || k <= 0) {
printf("Error cont\n");
return;
}
ListNode *pPrev = *prev, *pTail = (*prev)->next;
ListNode *pA = (*prev), *pB = (*prev)->next, *pTmp = nullptr;
while(k-- > 0 && pB) {
pTmp = pB->next;
pB->next = pA;
pA = pB;
pB = pTmp;
}
pTail->next = pB;
pPrev->next = pA;
*prev = pTail;
}
ListNode* reverseKGroup(ListNode* head, int k) {
if(!head || k <= 1 || !head->next){
return head;
}
ListNode pHead(0, head);
ListNode *pPrev = &pHead, *pNext = pHead.next;
while(pNext) {
int i =0 ;
for(;i<k&&pNext;i++) {
pNext = pNext->next;
}
if(i<k) {break;}
reverseRange(&pPrev, k);
}
return pHead.next;
}
- 删除链表的倒数第K个结点
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(!head || n <= 0) return head;
ListNode pHead(0, head);
ListNode *p1 = &pHead, *p2 = &pHead;
int i =0;
for(;i <n && p1->next; i++){
p1= p1->next;
}
if(i <n ) return head;
while(p1->next) {
p1 = p1->next;
p2 = p2->next;
}
p2->next = p2->next->next;
return pHead.next;
}
- 判断链表中是否有环
bool hasCycle(ListNode *head) {
if(!head || !head->next) { return false; }
ListNode *p1 = head, *p2 = head;
while(p1 && p2 && p2->next) {
p1 = p1->next;
p2 = p2->next->next;
if (p1 == p2) { return true; }
}
return false;
}
- 链表排序
ListNode* sortList(ListNode* head) {
if(!head||!head->next) return head;
if(!head->next->next) {
int &a = head->val, &b = head->next->val;
if(a>b) swap(a, b);
return head;
}
ListNode *p1 = head, *p2 = head;
while(p2 && p2->next){
p1 = p1->next;
p2 = p2->next->next;
}
ListNode *head2 = p1->next;
p1->next = nullptr;
ListNode pHead;
ListNode *l1 = sortList(head), *l2 = sortList(head2), *p = &pHead;
while(l1 && l2) {
if(l1->val < l2->val) {
p->next = l1;
l1 = l1->next;
} else {
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
if(l1) p->next = l1;
if(l2) p->next = l2;
return pHead.next;
}
排序变换 - 链表
- 合并两个有序链表
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(!l1)return l2;
if(!l2)return l1;
ListNode head(0);
auto p=&head;
while(l1&&l2){
if(l1->val>l2->val){
p->next=l2;
l2=l2->next;
p=p->next;
}else{
p->next=l1;
l1=l1->next;
p=p->next;
}
}
if(!l1&&l2){p->next=l2;}
else if(l1&&!l2){p->next=l1;}
return head.next;
}
双指针法 - 数组
- 将数组中的所有0移动到末尾
void moveZeroes(vector<int>& nums) {
if(nums.empty()) {
return;
}
deque<int> q;
for(int i = 0; i < nums.size(); i++) {
if(nums[i] == 0){
q.push_back(i);
} else {
if(!q.empty()){
swap(nums[i], nums[q.front()]);
q.pop_front();
q.push_back(i);
}
}
}
}
void moveZeroes(vector<int>& nums) {
int n = nums.size(), left = 0, right = 0;
while (right < n) {
if (nums[right]) {
swap(nums[left], nums[right]);
left++;
}
right++;
}
}
- 接雨水
int trap(vector<int>& height) {
int n = height.size();
int Lmax=0, Rmax=0, sum=0;
vector<int> maxL(n, 0), maxR(n, 0);
for(int i =0;i <n;i++){
Lmax=max(Lmax, height[i]);
maxL[i]=Lmax;
}
for(int i=n-1; i>=0;i--){
Rmax=max(Rmax, height[i]);
maxR[i]=Rmax;
}
for(int i=0;i<n;i++){
sum+=(max(0,min(maxR[i],maxL[i])-height[i]));
}
return sum;
}
- 盛水最多的容器
int maxArea(vector<int>& height) {
int i = 0, j = height.size() - 1;
int ans = 0;
for(;i<=j;) {
int h1 = height[i], h2 = height[j];
ans = max(ans, min(h1, h2) * (j-i));
h1 > h2 ? j-- : i++;
}
return ans;
}
- 删除排序数组中的重复项
int removeDuplicates(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();
int i = 1, j = 1, last = nums[0];
for(;j<nums.size();j++) {
if(nums[j] != last) {
last=nums[j];
swap(nums[i], nums[j]);
i++;
}
}
return i;
}
计数原理
- 出现一半次数以上的元素
int majorityElement(vector<int>& nums) {
if (nums.empty()) return 0;
int times = 1, prev = nums[0];
for(int i = 1; i< nums.size(); i ++){
if(prev == nums[i]){
times++;
} else {
times--;
if(times <= 0){
times = 1;
prev = nums[i];
}
}
}
return prev;
}
- 跳跃游戏
bool canJump(vector<int>& nums) {
int k = 0;
for(int i = 0; i < nums.size(); i++) {
if(i > k) return false;
k = max(k, nums[i] + i);
}
return true;
}
字符串
- 最长公共前缀
string longestCommonPrefix(vector<string>& strs) {
if(strs.empty()) return "";
int i = 0, t = 0;
for(;;i++) {
if(i>=strs[0].size()) break;
char c = strs[0][i];
for(auto &s: strs) {
if(i>=s.size() || s[i]!=c) {
t = 1;
break;
}
}
if(t) break;
}
return string(strs[0].begin(), strs[0].begin()+i);
}
区间问题
- 区间合并
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> res;
if(intervals.empty()) return res;
sort(intervals.begin(), intervals.end(), [](const vector<int> &l1, const vector<int> &l2){
return l1[0] < l2[0];
});
int n = intervals.size();
for(int i = 0;i < n; i++) {
int start = intervals[i][0];
int end = intervals[i][1];
i++;
for(;i<n && end >= intervals[i][0];i++){
end = max(end, intervals[i][1]);
}
res.push_back(vector<int>{start,end});
i--;
}
return res;
}
回溯法
- 组合问题 - 子集
class Solution {
public:
vector<int> r;
vector<vector<int>> res;
void recall(vector<int> &nums, int start) {
res.push_back(r);
for(int i =start; i< nums.size(); i++){
r.push_back(nums[i]);
recall(nums, i +1);
r.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
recall(nums ,0);
return res;
}
};
- 组合问题 - 全排列
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
res.push_back(nums);
while(next_permutation(nums.begin(), nums.end())){
res.push_back(nums);
}
return res;
}
数字转换
- 罗马数字转整数
int to_num(char c) {
switch(c) {
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
default : return 0;
}
return 0;
}
int romanToInt(string s) {
int sum = 0;
for(int i =0 ;i < s.size() - 1; i++){
if(to_num(s[i]) < to_num(s[i+1])){
sum -= to_num(s[i]);
} else {
sum += to_num(s[i]);
}
}
sum+=to_num(s[s.size()-1]);
return sum;
}
矩阵问题
- 顺时针旋转矩阵
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for(int i=0;i<n;i++) {
for(int j=0;j<(n-i);j++){
// printf("swap [%d,%d]%d, %d\n",i, j,matrix[i][j], matrix[n-i-1][n-j-1]);
swap(matrix[j][i], matrix[n-i-1][n-j-1]);
}
}
for(int i=0;i<n/2;i++){
swap(matrix[i], matrix[n-i-1]);
}
}