2020刷题

2020刷题

动态规划

基本思想

问题的最优解如果可以由子问题的最优解得到,则可以先求子问题的最优解,再构造原问题的最优解;若原问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解

斐波那契数列

leetcode地址

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <deque>

using namespace std;

class Solution {
public:
    int fib(int n) {
        // 初始条件处理
        int first = 0, second = 1;
        if (n == 0)
            return first;
        if (n == 1)
            return second;
        
        int res = 0;
        for (int i = 2; i <= n; i++){  // for和while循环均可
            res = (first + second) % (int)(1e9+7);
            first = second;
            second = res;
        }
        return res;
    }
};

int main()
{   
    Solution s;
    cout << s.fib(6) << endl;
    return 0;  
}

背包问题

参考1 参考2

  • 01背包:每件物品只有一个
  • 完全背包:物品数量无限,对于第i件物品,选择拿0,1,2...件,直到超过背包的大小(遍历的时候增加一层循环)
  • 多重背包问题:物品的数量有限,两个限制条件:物品数量和背包大小
  • 多维背包问题:物品的重量和体积两个限制条件,此时动态数组为三维的
  • 分组背包:每个组内的物品最多只能选一件,动态数组为前k组物品花费v能取得的最大权值
  • 总件数最小,多少件物品可以装满背包等等
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <deque>

using namespace std;

int bag_1(vector<int> weight, vector<int>value, int size){
    // 01背包问题
    // 每件物品只有一个,value和weight都大于0
    // 物品不可拆分
    // weight={2, 3, 4, 5}, value={3, 4, 5, 6}
    int m =  weight.size(), n = size;
    vector<vector<int> > dp(m + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; i++){
        for (int j = 1; j <= n; j++){
            if (weight[i - 1] > j){
                dp[i][j] = dp[i - 1][j];
            }
            else{
                // 选择是否拿第i件物品
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
            }
        }
    }
    return dp[m][n];
}

int bag_2(vector<int> weight, vector<int>value, int size){
    // 完全背包问题
    // 每件物品数量无限
    // weight={2, 3, 4, 5}, value={3, 4, 5, 6}
    int m =  weight.size(), n = size;
    vector<vector<int> > dp(m + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; i++){
        for (int j = 1; j <= n; j++){
            for (int k = 0; k * weight[i - 1] <= j; k++){
                // 选择拿几个i物品
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - k * weight[i - 1]] + k * value[i - 1]);
            }
        }
    }
    return dp[m][n];
}

int main()
{   
    vector<int> weight = {2,2,6,6,6,2,2,2};
    vector<int> value = {5,5,8,8,8,10,10,10};
    cout << bag_1(weight, value, 10) << endl;
    return 0;  
}

打家劫舍

leetcode地址

// 打家劫舍1
class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) return 0;
    
        // 子问题:
        // f(k) = 偷 [0..k) 房间中的最大金额

        // f(0) = 0
        // f(1) = nums[0]
        // f(k) = max{ rob(k-1), nums[k-1] + rob(k-2) }

        int size = nums.size();
        if (size == 1) return nums[0];

        vector<int> dp(size, 0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for (int i = 2; i < size; i++){
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[size - 1];
    }
};

// 打家劫舍2
class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) return 0;

        // 环状排列以为这第一个房子和最后一个房子只能选择一个
        // 选择第一个房子:nums[0:n-2]
        // 不选择第一个房子:nums[1:n-1]
        // 取两者情况的最大值

        int size = nums.size();
        if (size == 1) return nums[0];
        int max_1 = rob1(nums, 0, size - 2);
        int max_2 = rob1(nums, 1, size - 1);
        return max(max_1, max_2);
    }
    int rob1(vector<int>& nums, int start, int end){
        int pre_max = 0;
        int cur_max = 0;
        for (int i = start; i <= end; i++){
            int temp = cur_max;
            cur_max = max(pre_max + nums[i], cur_max);
            pre_max = temp;
        }
        return cur_max;
    }
};

最长公共子序列LCS

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m = text1.size(), n = text2.size();
        vector<vector<int> > dp(m + 1, vector<int>(n + 1, 0));
        // dp[i][j] 表示text1的前i个字符和text2的前j个字符的最长公共子序列
        // 注意第一行,第一列是初始条件,需要赋值为0
        for (int i = 1; i <= m; i++){
            for (int j = 1; j <= n; j++){
                if (text1[i - 1] == text2[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                else{
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[m][n];
    }
};

零钱问题

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        // 动态规划解法
        // f(i)表示凑成金额i所需最少的硬币个数
        // 每次判断时,遍历所有的硬币面值
        vector<int> dp(amount + 1, amount + 1);  // 注意初始化,硬币数的最大值
        dp[0] = 0;    // 0可以用0个硬币凑成
        for (int i = 1; i <= amount; i++){
            for (int j = 0; j < coins.size(); j++){
                // 对最后一枚硬币进行遍历
                if (coins[j] <= i){
                    dp[i] = min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] == amount + 1 ? -1 : dp[amount];
    }
};

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        // 动态规划:二维动态规划表
        int m = coins.size(), n = amount;
        vector<vector<int> > dp(m + 1, vector<int>(n + 1, 0));
        for (int i = 1; i <= n; i++){
            dp[0][i] = 0;
        }
        for (int i = 0; i <= m; i++){
            // 注意初始化为1
            dp[i][0] = 1;
        }

        // 注意m,n的顺序
        for (int i = 1; i <= m; i++){
            for (int j = 1; j <= n; j++){
                for (int k = 0; k * coins[i - 1] <= j; k++){
                    // 取0,1,2...枚第i种硬币
                    dp[i][j] += dp[i - 1][j - k * coins[i - 1]];
                }
            }
        }
        return dp[m][n];
    }
};

股票问题

买卖股票的最佳时机

买卖股票的最佳时机 II

买卖股票的最佳时机 III

买卖股票的最佳时机 IV

最佳买卖股票时机含冷冻期

买卖股票的最佳时机含手续费

回溯法

基本思想

又称试探法,逐步进行探索,发现选择不是正确解,就退回一步重新选择。一般使用递归实现

  • 递归出口
  • 递归函数的参数
  • 递归函数的处理过程

单词搜索

leetcode地址

class Solution {
public:
    bool dfs(vector<vector<char>>& board, int i, int j, string word, 
    int len, vector<vector<bool>> &visit){
        // i, j 访问到矩阵的哪个元素
        // len访问到字符串哪个元素
        if (len >= word.size())
            return true;

        bool res = false;
        if (i < board.size() && j < board[0].size() && visit[i][j] == false && board[i][j] == word[len]){
            visit[i][j] = true;
            if (dfs(board, i, j - 1, word, len + 1, visit) || dfs(board, i, j + 1, word, len + 1, visit)
            || dfs(board, i - 1, j, word, len + 1, visit) || dfs(board, i + 1, j, word, len + 1, visit))
                res = true;
            visit[i][j] = false;
        }
        return res;
    }

    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size(), n = board[0].size();
        vector<vector<bool> > visit(m, vector<bool>(n, false));
        
        int len = 0, i = 0, j = 0;
        bool res;
        for (int i = 0; i < m; i++){
            for (int j = 0; j < n; j++){
                res = dfs(board, i, j, word, len, visit);
                if (res == true)
                    return true;
            }
        }
        return false;
    }
};
// 不需要标记矩阵
class Solution {
public:
    bool dfs(vector<vector<char>>& board, int i, int j, string word, int len){
        // i, j 访问到矩阵的哪个元素
        // len 访问到字符串哪个元素
        if (len >= word.size())
            return true;

        bool res = false;
        if (i < board.size() && j < board[0].size() && board[i][j] == word[len]){
            char temp = board[i][j];
            board[i][j] = '#';        // 避免重复访问
            if (dfs(board, i, j - 1, word, len + 1)    // 访问下一个元素
            || dfs(board, i, j + 1, word, len + 1)
            || dfs(board, i - 1, j, word, len + 1) 
            || dfs(board, i + 1, j, word, len + 1))
                res = true;
            board[i][j] = temp;      // 重置为初始状态
        }
        return res;
    }

    bool exist(vector<vector<char>>& board, string word) {
        if (board.empty()) return false;

        int m = board.size(), n = board[0].size();
        for (int i = 0; i < m; i++){
            for (int j = 0; j < n; j++){
                // 从每个格子出发,若成功,直接返回
                if(dfs(board, i, j, word, 0))
                    return true;
            }
        }
        return false;
    }
};

解数独

leetcode地址


全排列

全排列1

全排列2

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > res;
        vector<int> visit;
        backtrack(res, nums, visit);
        return res;
    }
    bool contain(vector<int> &visit, int num){
        int i;
        for (i = 0; i < visit.size(); i++){
            if (visit[i] == num)
                break;
        }
        return i == visit.size() ? false : true;
    }
    void backtrack(vector<vector<int> > &res, vector<int>& nums, vector<int> &visit){
        // 结束条件
        if (visit.size() == nums.size()){
            res.push_back(visit);
            return;
        }
        // 做出选择
        // 进入决策树
        // 撤销选择
        for (int i = 0; i < nums.size(); i++){
            if (contain(visit, nums[i]) == true) continue;
            visit.push_back(nums[i]);
            backtrack(res, nums, visit);
            visit.pop_back();
        }
        return;
    }
};


class Solution {
public:
    vector<vector<int> > res;
    vector<int> sol;
    vector<int> nums;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        sort(nums.begin(), nums.end());
        this -> nums = nums;
        dfs(used);
        return res;
    }
    void dfs(vector<bool> &used){
        if (sol.size() == nums.size()){
            res.push_back(sol);
            return;
        }
        for (int i = 0; i < nums.size(); i++){
            // 两种情况:当前值用过了和当前值未用过
            // 1. nums[i-1] 没用过,说明回溯到了同一层,此时接着使用nums[i]会与nums[i-1]重复
            // 2. nums[i-1] 用过了, 说明此时在nums[i-1]的下一层,相等不会重复
            if (used[i] || (i > 0 && !used[i-1] && nums[i] == nums[i-1]))
                continue;
            used[i] = true;
            sol.push_back(nums[i]);
            dfs(used);
            sol.pop_back();
            used[i] = false;
        }
    }
};

N皇后

N皇后

class Solution {
public:
    vector<vector<string> > res;
    vector<string> cur;
    vector<vector<string>> solveNQueens(int n) {
        vector<string> cur(n, string(n, '.'));
        this -> cur = cur;
        backtrack(0);
        return res;
    }
    void backtrack(int row){
        if (row >= cur.size()){
            res.push_back(cur);
            return;
        }

        for (int i = 0; i < cur.size(); i++){
            if (valid(row, i) == false)  continue;
            cur[row][i] = 'Q';
            backtrack(row + 1);
            cur[row][i] = '.';
        }
        return;
    }
    bool valid(int row, int col){
        bool flag = true;
        // 行无冲突
        // 其实行无需检测,因为是对当前行的遍历
        for (int i = 0; i < cur.size(); i++){
            if (cur[row][i] == 'Q'){
                flag = false;
                break;
            }
        }
        // 列检测
        for (int i = 0; i < cur.size() && flag == true; i++){
            if (cur[i][col] == 'Q'){
                flag = false;
                break;
            }
        }
        // 左上方无冲突
        for (int i = row - 1, j = col - 1; flag == true && i >= 0 && j >= 0; i--, j--){
            if (cur[i][j] == 'Q'){
                flag = false;
                break;
            }
        }
        // 右上方无冲突
        for (int i = row - 1, j = col + 1; flag == true && i >= 0 && j < cur.size(); i--, j++){
            if (cur[i][j] == 'Q'){
                flag = false;
                break;
            }
        }
        return flag;
    }
};

二叉树

链表

BFS

一般用来求解:从一个点,到另一个终点,求最短路径

双向BFS:起点和终点一起遍历

二叉树的最小深度

二叉树的最大深度

打开转盘锁

// 最小深度
class Solution {
public:
    int minDepth(TreeNode* root) {
        if (!root) return 0;

        int step = 1;
        queue<TreeNode*> q;
        q.push(root);        // 初始化队列
        while (!q.empty()){
            int size = q.size();
            for (int i = 0; i < size; i++){
                TreeNode* cur = q.front();
                q.pop();
                // 判断是否到达终止条件
                if (cur -> left == NULL && cur -> right == NULL)
                    return step;
                if (cur -> left != NULL)
                    q.push(cur -> left);
                if (cur -> right != NULL)
                    q.push(cur -> right);
            }
            step++;
        }
        return step;
    }
};

二分搜索

  • 基本二分
  • 左边界二分
  • 右边界二分
int basic_binary(vector<int> nums, int target){
    // 左右闭区间
    int left = 0, right = nums.size() - 1;
    // 终止条件:left > right
    while (left <= right){
        // 防止溢出
        // 注意/不能直接换成>>,因为>>是最后计算的
        int mid = left + (right - left) / 1;
        if (nums[mid] == target)
            return mid;
        else if (nums[mid] > target){
            right = mid - 1;
        }
        else if (nums[mid] < target){
            left = mid + 1;
        }
    }
    return -1;
}

int left_binary(vector<int> nums, int target){
    // 寻找左侧边界的二分搜索
    // 左右闭区间, 搜索区间为[mid, right]
    int left = 0, right = nums.size() - 1;
    // 终止条件:left > right
    while (left <= right){
        // 防止溢出
        int mid = left + (right - left) / 2;
        if (nums[mid] == target)
            // 搜索区间为[left, mid - 1]
            right = mid - 1;
        else if (nums[mid] > target){
            // 搜索区间为[left, mid - 1]
            right = mid - 1;
        }
        else if (nums[mid] < target){
            // 搜索区间为[mid + 1, right]
            left = mid + 1;
        }
    }
    if (left >= nums.size() || nums[left] != target){
        return -1;
    }
    return left;
}

int right_binary(vector<int> nums, int target){
    // 寻找右侧边界的二分搜索
    // 左右闭区间, 搜索区间为[mid, right]
    int left = 0, right = nums.size() - 1;
    // 终止条件:left > right
    while (left <= right){
        // 防止溢出
        int mid = left + (right - left) / 2;
        if (nums[mid] == target)
            // 搜索区间为[mid + 1, right]
            left = mid + 1;
        else if (nums[mid] > target){
            // 搜索区间为[left, mid - 1]
            right = mid - 1;
        }
        else if (nums[mid] < target){
            // 搜索区间为[mid + 1, right]
            left = mid + 1;
        }
    }
    if (right < 0 || nums[right] != target){
        return -1;
    }
    return right;
}

滑动窗口

  • 双指针
  • 快慢指针

最小覆盖子串

class Solution {
public:
    string minWindow(string s, string t) {
        // 滑动窗口: [left, right)
        map<char, int> need, window;
        for (char c:t)
            need[c]++;
        
        int left = 0, right = 0;
        int valid = 0;    // 表示窗口中满足need条件的字符数
        int start = 0, len = INT32_MAX;
        while (right < s.size()){
            char c = s[right];   // 即将移入窗口的字符
            right++;             // 右移窗口
            if (need.count(c)){
                window[c]++;
                if (window[c] == need[c]){
                    valid++;
                }
            }
            while (valid == need.size()){
                // 更新最小覆盖子串
                if (right - left < len){
                    start = left;
                    len = right - left;
                }
                // d为即将移除窗口的字符
                char d = s[left];
                left++;
                if (need.count(d)){
                    if (window[d] == need[d]){
                        valid--;
                    }
                    window[d]--;
                }
            }
        }
        return len == INT32_MAX ? "" : s.substr(start, len);
    }
};

双指针

环形链表参考1

环形链表2

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (!head) return false;
        ListNode* slow = head, *fast = head;
        while (fast != NULL && fast -> next != NULL){
            fast = fast -> next -> next;
            slow = slow -> next;
            if (fast == slow){
                return true;
            }
        }
        return false;
    }
};

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (!head) return NULL;
        ListNode *slow = head, *fast = head;
        while (fast != NULL && fast -> next != NULL){
            fast = fast -> next -> next;
            slow = slow -> next;
            if (fast == slow){
                slow = head;
                while (fast != slow){
                    fast = fast -> next;
                    slow = slow -> next;
                }
                return slow;
            }
        }
        return NULL;
    }
};

常见

  • 曼哈顿距离:参考 思路为x,y分开计算,然后使用前缀和和后缀和(注意思想

邮局选址

bool cmp(int p1, int p2){
    return p1 < p2;
}

void print(vector<int> &nums){
    cout << "-----------" << endl;
    for (auto num:nums){
        cout << num << endl;
    }
}

int dist(vector<int> &nums, int target){
    vector<int> pre(nums.size(), 0), aft(nums.size(), 0);
    sort(nums.begin(), nums.end(), cmp);
    int index = 0;
    for (; index < nums.size(); index++){
        if (nums[index] > target){
            break;
        }
    }
    index--;
    
    int sum = 0;
    for (int i = 0; i < nums.size(); i++){   // 前缀和
        sum += nums[i];
        pre[i] = sum;
    }
    sum = 0;
    for (int i = nums.size() - 1; i >= 0; i--){  // 后缀和
        sum += nums[i];
        aft[i] = sum;
    }
    
    cout << index << endl;
    return 0;
}

int main()
{
    vector<int> nums = {1, 5, 6, 7, 2, 3, 4, 8, 9};
    dist(nums, 4);
	return 0;
}

自定义sort

struct Point{
    int x;
    int y;
    Point(int new_x, int new_y): x(new_x), y(new_y){}
};

void print(const Point p){
    cout << "(" << p.x << ", " << p.y << ")" << endl;
}

bool cmp(const Point p1, const Point p2){
    return p1.x < p2.x;  // 递增排序
    // return p1.x < p2.x;  // 递减排序
}

void my_sort(){
    vector<Point> p;
    p.push_back(Point(1, 3));
    p.push_back(Point(5, 2));
    p.push_back(Point(4, 9));
    p.push_back(Point(2, 1));
    sort(p.begin(), p.end(), cmp);
    for (int i = 0; i < p.size(); i++){
        print(p[i]);
    }
}

x的n次方

int pow(int x, int n){
    if (n == 0)  return 1;
    if (x == 1)  return 1;

    int res = 1;
    if (n % 2 == 0){
        int temp = pow(x, n / 2);
        res = temp * temp;
    }
    else{
        int temp = pow(x, n / 2);
        res = temp * temp * x;
    }
    return res;
}

kmp算法

快速进行字符串模式匹配,暴力法需要进行指针回溯,复杂度高

B站讲解

kmp求最短循环字串 参考2

// 右值匹配, 蛮力算法
int pipei(string str, string pattern){
    // 返回子串在主串中的位置
    int i = 0, j = 0;
    while (i < str.size() && j < pattern.size()){
        if (str[i] == pattern[j]){
            i++;
            j++;
        }
        else{
            i = i - j + 1;
            j = 0;
        }
    }
    return j == pattern.size() ? i - j : -1;
}

int main()
{
    string str = "acdfraxyxyrrwwe";
    string pattern = "xyxy";
    cout << pipei(str, pattern) << endl;
	return 0;
}
void getNext(string str, vector<int> &next){
    // a  b a b c d a b a b b d的next数组为:
    //[-1 0 0 1 2 0 0 1 2 3 4 0]
    // 用字符串本身与字符串进行匹配
    // 当前字符匹配: next[i + 1] = next[i] + 1 = j + 1
    // 当前字符不匹配: j = next[j]
    next[0] = -1;
    int i = 0, j = -1;
    while (i < next.size() - 1){
        if (j == -1 || str[i] == str[j]){
            i++;
            j++;
            next[i] = j;
        }
        else{
            j = next[j];
        }
    }
}

// kmp算法
int pipei(string str, string pattern){
    // i指向主串,j指向模式串
    vector<int> next(pattern.size(), 0);
    getNext(pattern, next);
    int i = 0, j = 0;
    // 特别注意:j可能为-1,但是size()的返回值为unsigned int
    // 需要先转成int再进行比较
    while (i < str.size() && j < (int)pattern.size()){
        if (j == -1 || str[i] == pattern[j]){
            i++;
            j++;
        }
        else{
            // 当前位置不匹配,j指向下一个位置
            j = next[j];
        }
    }
    return j == pattern.size() ? i - j : -1;
}

int main()
{
    string str = "ababcdababbd";
    string pattern = "daba";
    cout << pipei(str, pattern) << endl;
	return 0;
}

生产者消费者

参考1 条件变量1 条件变量2

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

sem_t sem;     // 定义全局的信号量结构
pthread_mutex_t mutex;   // 定义全局互斥锁
// pthread_mutex_lock(&mutex)  // 阻塞加锁,加锁成功返回0
// pthread_mutex_trylock(&mutex)  // 非阻塞加锁,线程不是挂起等待
// pthread_mutex_unlock(&mutex)  // 解锁

void A(){
    cout << "A" << endl;
    sem_post(&sem);
}

void B(){
    sem_wait(&sem);
    cout << "B" << endl;
}

int main()
{
    pthread_t privider, handler;
    sem_init(&sem, 0, 0);               // 初始化信号量
    pthread_mutex_init(&mutex, NULL);   // 初始化锁
    
    pthread_create(&privider, NULL, (void*)&A, NULL);
    pthread_create(&handler, NULL, (void*)&B, NULL);
    
    pthread_join(privider, NULL);  // 获取另一个线程的终止状态,释放该线程的资源
    pthread_join(handler, NULL);
    sem_destroy(&sem);
    return 0;  
}

nSum问题

two sum

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<int> res;
        int left = 0, right = nums.size() - 1;
        while (left < right){
            if (nums[left] + nums[right] == target){
                res.push_back(left);
                res.push_back(right);
                return res;
            }
            else if (nums[left] + nums[right] > target){
                right--;
            }
            else{
                left++;
            }
        }
        return res;
    }
};

three sum

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int> > res;
        if (nums.size() < 3)  return res;

        sort(nums.begin(), nums.end());
        int a;
        for (int i = 0; i < nums.size(); i++){
            if (i > 0 && nums[i] == nums[i -1])
                continue;
            a = nums[i];
            int low = i + 1, high = nums.size() - 1;
            while (low < high){
                int left = nums[low], right = nums[high];
                if (left + right < - a){
                    low++;
                }
                else if (left + right > - a){
                    high--;
                }
                else{
                    vector<int> cur;
                    cur.push_back(a);
                    cur.push_back(left);
                    cur.push_back(right);
                    res.push_back(cur);
                    while (low < high && nums[low] == left)  low++;
                    while (low < high && nums[high] == right)  high--;
                }
            }
        }
        return res;
    }
};

洗牌算法

通过蒙特卡洛算法进行随机性验证,即多次洗牌,看各个结果出现次数是否平均

void shuffle(vector<int>nums){
    int n = nums.size();
    for (int i = 0; i < n; i++){
        int rand = randInt(i, n - 1); // [i, n-1]随机选取一个元素
        swap(nums[i], nums[rand]);
    }
}

快排

int partition(vector<int> &nums, int left, int right){
    int pivot = nums[left];
    int index = left + 1; // 指向大于pivot的第一个元素
    for (int i = left + 1; i <= right; i++){
        if (nums[i] < pivot){
            swap(nums[index], nums[i]);
            index++;
        }
    }
    index--;  // 需要减1后交换
    swap(nums[left], nums[index]);
    return index;
}

void quick_sort(vector<int> &nums, int left, int right){
    if (left >= right) return;
    int index = partition(nums, left, right);
    quick_sort(nums, left, index - 1);
    quick_sort(nums, index + 1, right);
}

int main()
{
    vector<int> nums = {6, 3, 7, 5, 2, 9, 1};
    quick_sort(nums, 0, 6);
    for (auto i:nums)
        cout << i << endl;
	return 0;
}

归并排序

void merge(vector<int> &nums, int left, int right, int mid){
    vector<int> temp;
    int i = left, j = mid + 1;
    while (i <= mid && j <= right){
        if (nums[i] <= nums[j]){
            temp.push_back(nums[i]);
            i++;
        }
        else{
            temp.push_back(nums[j]);
            j++;
        }
    }
    while (i <= mid){
        temp.push_back(nums[i]);
        i++;
    }
    while (j <= right){
        temp.push_back(nums[j]);
        j++;
    }
    for (int i = left; i <= right; i++){
        nums[i] = temp[i - left];  // 注意temp的下标
    }
}

void merge_sort(vector<int> &nums, int left, int right){
    if (left >= right) return;
    int mid = (left + right) / 2;
    merge_sort(nums, left, mid);
    merge_sort(nums, mid + 1, right);
    merge(nums, left, right, mid);
}

int main()
{
    vector<int> nums = {6, 3, 7, 5, 2, 9, 1, 0};
    merge_sort(nums, 0, 7);
    for (auto i:nums)
        cout << i << endl;
	return 0;
}

鸡蛋掉落

鸡蛋掉落 看题解

智力题

男孩女孩

两个孩子,其中一个为男孩,另一个也是男孩的概率是多少?

生日悖论

23个人中,至少两个人生日是同一天的概率达到50%

三门问题

posted @ 2020-09-25 23:41  happy_fan  阅读(118)  评论(0编辑  收藏  举报