算法-基础知识汇总

算法

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

详细内容

  1. 顺序容器
    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;
  1. 关联容器
    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;
  1. 无序关联容器
    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;
  1. 容器适配器
    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;

数据结构

二叉树

  1. 前序遍历
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;
    }
};
  1. 中序遍历
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;
    }
};
  1. 后续遍历

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;
    }
};
  1. 分层遍历
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;
}

  1. 判断对称二叉树
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);
    }
};
  1. 判断平衡树
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);
    }
};
  1. 分层打印二叉树
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;
}
  1. 二叉树的最大直径
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;
    }
};
  1. 验证二叉搜索树
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);
}
  1. 不同的二叉搜索树的组合数
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];
}

双指针法 - 链表

  1. 找到相交链表的重合节点
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;
}
  1. 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;
}
  1. 删除链表的倒数第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;
}
  1. 判断链表中是否有环
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;
}
  1. 链表排序
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;
}

排序变换 - 链表

  1. 合并两个有序链表
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;
}

双指针法 - 数组

  1. 将数组中的所有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++;
    }
}
  1. 接雨水
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;
}
  1. 盛水最多的容器
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;
}
  1. 删除排序数组中的重复项
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;
}

计数原理

  1. 出现一半次数以上的元素
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;
}
  1. 跳跃游戏
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;
}

字符串

  1. 最长公共前缀
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);
}

区间问题

  1. 区间合并
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;
}

回溯法

  1. 组合问题 - 子集
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;
    }
};
  1. 组合问题 - 全排列
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;
}

数字转换

  1. 罗马数字转整数
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;
}

矩阵问题

  1. 顺时针旋转矩阵
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]);
    }
}
posted @ 2021-01-18 00:26  liutianchen  阅读(96)  评论(0编辑  收藏  举报