【递归、搜索与回溯】综合练习 {回溯恢复现场;剪枝优化}

一、经验总结

在递归算法中某些变量需要在回溯到上一层递归后恢复现场(如递归路径),恢复现场的方法有:

  1. 全局变量手动恢复:如果该变量的类型为自定义类型(vector, string等)则推荐定义为全局变量。如果将自定义类型数据作为函数参数进行传递(局部变量),那么每层递归都要进行构造和析构工作,消耗很大。定义为全局变量则不存在这个问题,但是全局变量需要在回溯到上一层后手动进行现场恢复;
  2. 局部变量自动恢复:如果该变量的类型为内置类型(int, double等)则推荐定义为函数参数(局部变量)。内置类型数据的创建和拷贝消耗相比手动恢复现场几乎可以忽略不记。如果该变量为局部变量(局部参数),则每层递归的变量都是全新、独立的变量不会相互影响,在回溯过程中能够自动实现“恢复现场”。

剪枝优化的方法有:

  1. 对于全排列题目使用全局或局部标记进行剪枝:全排列Ⅰ(全局标记)、全排列Ⅱ(局部标记);可以使用一些巧妙地方式构建哈希映射,如题目:N皇后(斜线映射)、解数独(区块映射)
  2. 对于具有无序性的集合,从当前位置的下一个位置向下递归:找子集、组合
  3. 对于具有特定约束条件的问题,根据其他特殊规则进行剪枝:括号生成(左右括号的数量关系)

二、相关编程题

2.1 找出所有子集的异或总和再求和

题目链接

1863. 找出所有子集的异或总和再求和 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    int sum;
    int XOR;
public:
    int subsetXORSum(vector<int>& nums) {
        DFS(nums,0);
        return sum;
    }

    void DFS(vector<int>& nums, int pos)
    {
        sum+=XOR;
        for(int i = pos; i < nums.size(); ++i)
        {
            XOR^=nums[i];
            DFS(nums, i+1);
            XOR^=nums[i]; //回溯恢复现场:异或消消乐
        }
    }
};

2.2 全排列Ⅱ

题目链接

47. 全排列 II - 力扣(LeetCode)

题目描述
在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    bool used[8];
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        DFS(nums, 0);
        return ret;
    }

    void DFS(vector<int>& nums, int pos)
    {
        if(pos == nums.size())
        {
            ret.push_back(path);
            return;
        }
        unordered_set<int> hash; //局部的哈希表
        for(int i = 0; i < nums.size(); ++i)
        {
            if(!used[i] && !hash.count(nums[i]))
            {
                hash.insert(nums[i]);
                path.push_back(nums[i]);
                used[i] = true;
                hash.insert(nums[i]);
                DFS(nums, pos+1);
                path.pop_back();
                used[i] = false;
            }
        }
    }
};

2.3 电话号码的字母组合

题目链接

17. 电话号码的字母组合 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<string> ret;
    string path;
    string strs[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public:
    vector<string> letterCombinations(string digits) {
        if(digits.size() == 0) return ret;
        DFS(digits, 0);
        return ret;
    }

    void DFS(string& digits, int pos)
    {
        if(pos == digits.size()) 
        {
            ret.push_back(path);
            return;
        }
        string &str = strs[digits[pos]-'0'];
        for(int i = 0; i < str.size(); ++i)
        {
            path.push_back(str[i]);
            DFS(digits, pos+1);
            path.pop_back();
        }
    }
};

2.4 括号生成

题目链接

22. 括号生成 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<string> ret;
    string path;
    int left, right;
public:
    vector<string> generateParenthesis(int n) {
        DFS(n);
        return ret;
    }
    void DFS(int n)
    {
        if(right == n)
        {
            ret.push_back(path);
            return;
        }

        if(left < n) //可以添加左括号
        {
            path.push_back('(');
            ++left;
            DFS(n);
            path.pop_back(); //恢复现场
            --left;
        }
        
        if(right < left) //可以添加右括号
        {
            path.push_back(')');
            ++right;
            DFS(n);
            path.pop_back(); //恢复现场
            --right;
        }
    }
};

2.5 组合

题目链接

77. 组合 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    int _k;
public:
    vector<vector<int>> combine(int n, int k) {
        _k = k;
        DFS(n, 1);
        return ret;
    }

    void DFS(int n, int pos)
    {
        if(path.size() == _k) 
        {
            ret.push_back(path);
            return;
        }

        for(int i = pos; i <= n; ++i)
        {
            path.push_back(i);
            DFS(n, i+1);
            path.pop_back();
        }
    }
};

2.6 目标和

题目链接

494. 目标和 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

//path是全局变量(超时):
class Solution {
    int _target, sum, ret;
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        _target = target;
        DFS(nums, 0);
        return ret;
    }

    void DFS(vector<int>& nums, int pos)
    {
        if(pos == nums.size())
        {
            if(sum == _target) ++ret;
            return;
        }
        //+
        sum+=nums[pos];
        DFS(nums, pos+1);
        sum-=nums[pos];
        //-
        sum-=nums[pos];
        DFS(nums, pos+1);
        sum+=nums[pos];
    }
};

//path是函数参数(更优):
class Solution {
    int _target, ret;
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        _target = target;
        DFS(nums, 0, 0);
        return ret;
    }

    void DFS(vector<int>& nums, int pos, int sum)
    {
        if(pos == nums.size())
        {
            if(sum == _target) ++ret;
            return;
        }
        //+
        DFS(nums, pos+1, sum+nums[pos]);
        //-
        DFS(nums, pos+1, sum-nums[pos]);
    }
};

2.7 组合总和

题目链接

39. 组合总和 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

//解法一:
class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    int _target;
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        _target = target;
        DFS(candidates, 0, 0);
        return ret;
    }
    
    void DFS(vector<int>& arr, int pos, int sum)
    {
        if(sum >= _target)
        {
            if(sum == _target)
                ret.push_back(path);
            return;
        }

        for(int i = pos; i < arr.size(); ++i)
        {
            path.push_back(arr[i]);
            DFS(arr, i, sum+arr[i]); //一个数字可以选择多次,从当前选中的位置i开始向后遍历递归
            path.pop_back();
        }
    }
};

//解法二:
class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    int _target;
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        _target = target;
        DFS(candidates, 0, 0);
        return ret;
    }
    
    void DFS(vector<int>& arr, int pos, int sum)
    {
        if(sum == _target)
        {
            ret.push_back(path);
            return;
        }
        if(sum > _target || pos == arr.size()) return;

        int i = 0;
        while(sum+i*arr[pos] <= _target) //等于也要向下递归
        {
            if(i>0) path.push_back(arr[pos]); //出现0次不需要添加数字
            DFS(arr, pos+1, sum+i*arr[pos]);
            ++i; 
        }
        //恢复现场
        while(--i) //出现0次不需要添加数字
        {
            path.pop_back();
        }
    }
};

2.8 字母大小写全排列

题目链接

784. 字母大小写全排列 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

 class Solution {
    vector<string> ret;
    string path;
public:
    vector<string> letterCasePermutation(string s) {
        DFS(s, 0);
        return ret;
    }
    
    void DFS(string &s, int pos)
    {
        if(pos == s.size())
        {
            ret.push_back(path);
            return;
        }
		//不变
        path.push_back(s[pos]);
        DFS(s, pos+1);
        path.pop_back();
		//变
        if(isalpha(s[pos]))
        {
            path.push_back(s[pos]^32);
            DFS(s, pos+1);
            path.pop_back();
        }
    }
};

2.9 优美的排列

题目链接

526. 优美的排列 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    int ret;
    bool used[16];
public:
    int countArrangement(int n) {
        DFS(n, 1);
        return ret;
    }
    void DFS(int n, int pos)
    {
        if(pos == n+1)
        {
            ++ret;
            return;
        }

        for(int i = 1; i <= n; ++i)
        {
            if(!used[i] && (i%pos==0 || pos%i==0))
            {
                used[i] = true;
                DFS(n, pos+1);
                used[i] = false;
            }
        }
    }
};

2.10 N皇后

题目链接

51. N 皇后 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<vector<string>> ret;
    vector<string> path;
    bool col[9];
    bool slant1[17], slant2[17]; //正斜线和反斜线哈希表
public:
    vector<vector<string>> solveNQueens(int n) {
        path.resize(n, string(n, '.'));
        DFS(n, 0);
        return ret;
    }

    void DFS(int n, int row)
    {
        if(row == n)
        {
            ret.push_back(path);
            return;
        }

        for(int i = 0; i < n; ++i)
        {
            //选中位置的下标[row, i] 
            int k1 = row-i+(2*n-1)/2; //正斜线的下标
            int k2 = row+i; //反斜线的下标
            if(!col[i] && !slant1[k1] && !slant2[k2])
            {
                col[i] = slant1[k1] = slant2[k2] = true;
                path[row][i] = 'Q';
                DFS(n, row+1);
                // 恢复现场
                col[i] = slant1[k1] = slant2[k2] = false;
                path[row][i] = '.';
            }
        }
    }
};

2.11 有效的数独

题目链接

36. 有效的数独 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        bool row[9][10] = {false};
        bool col[9][10] = {false};
        bool block[3][3][10] = {false};
        int n = board.size();
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(board[i][j] != '.')
                {
                    int num = board[i][j]-'0';
                    if(row[i][num] || col[j][num] || block[i/3][j/3][num])
                    {
                        return false;
                    }
                    else
                    {
                        row[i][num] = col[j][num] = block[i/3][j/3][num] = true;
                    } 
                } 
            }
        }
        return true;
    }
};

2.12 解数独

题目链接

37. 解数独 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    bool checkRow[9][10];
    bool checkCol[9][10];
    bool checkBlock[3][3][10];
    int n;
public:
    void solveSudoku(vector<vector<char>>& board) {
        n = board.size();
        //预处理,将已有的数字添加到各哈希表
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(board[i][j] != '.')
                {
                    int k = board[i][j]-'0';
                    checkRow[i][k] = checkCol[j][k] = checkBlock[i/3][j/3][k] = true;
                }
            }
        }
        //从0,0位置开始进行递归
        DFS(board, 0, 0);
    }
    bool DFS(vector<vector<char>>& board, int row, int col)
    {
        int j = col;
        for(int i = row; i < n; ++i)
        {
            for(; j < n; ++j)
            {
                if(board[i][j] == '.')
                {
                    for(int k = 1; k <= 9; ++k)
                    {
                        if(!checkRow[i][k] && !checkCol[j][k] && !checkBlock[i/3][j/3][k])
                        {
                            checkRow[i][k] = checkCol[j][k] = checkBlock[i/3][j/3][k] = true;
                            board[i][j] = k+'0';
                            if(!DFS(board, i, j))
                            {
                                //如果当前选择的数字使得后续的填写无法继续,恢复现场,重新选择数字
                                checkRow[i][k] = checkCol[j][k] = checkBlock[i/3][j/3][k] = false;
                                board[i][j] = '.';
                            }  
                            else
                                //如果当前选择的数字使得后续填写完成,直接返回true。
                                return true;
                        }
                    }
                    return false; //9个数字都试过不行,返回false
                }
            }
            j = 0; //注意这里的写法,一行遍历完j还是要还原为0
        }
        //将所有的空格填写完,返回true
        return true;
    }
};

2.13 单词搜索

题目链接

79. 单词搜索 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int m, n;
    bool used[6][6];
public:
    bool exist(vector<vector<char>>& board, string word) {
        m = board.size(), n = board[0].size();
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(board[i][j] == word[0])
                {
                    used[i][j] = true;
                    if(DFS(board, i, j, word, 0))
                        return true;
                    used[i][j] = false;
                }
            }
        }
        return false;
    }

    bool DFS(vector<vector<char>>& board, int r, int c, string word, int pos)
    {
        if(pos == word.size()-1) return true;
        for(int i = 0; i < 4; ++i)
        {
            int x=r+dx[i], y=c+dy[i];
            if(x>=0 && x<m && y>=0 && y<n && !used[x][y] && board[x][y] == word[pos+1])
            {
                used[x][y] = true;
                if(DFS(board, x, y, word, pos+1))
                    return true;
                used[x][y] = false;
            }
        }
        return false;
    }
};

2.14 黄金矿工

题目链接

1219. 黄金矿工 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

从每一个非零位置开始进行一次DFS,当一条路径走到尽头时更新一次结果(统计最大值)

编写代码

class Solution {
    int ret;
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    int visited[15][15];
    int m, n;
public:
    int getMaximumGold(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(grid[i][j] != 0)
                {
                    visited[i][j] = true;
                    DFS(grid, i, j, grid[i][j]);
                    visited[i][j] = false;
                }
            }
        }
        return ret;
    }

    void DFS(vector<vector<int>>& grid, int r, int c, int sum)
    {
        bool flag = false;
        for(int i = 0; i < 4; ++i)
        {
            int x=r+dx[i], y=c+dy[i];
            if(x>=0 && x<m && y>=0 && y<n && !visited[x][y] && grid[x][y]!=0)
            {
                flag = true;
                visited[x][y] = true;
                DFS(grid, x, y, sum+grid[x][y]);
                visited[x][y] = false;
            }
        }
        if(!flag) ret = max(ret, sum); //一条路径走到头更新结果     
    }
};

2.15 不同路径Ⅲ

题目链接

980. 不同路径 III - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

从数字1开始进行DFS,当递归遍历到数字2时,检查一下路径中0的个数:如果通过了所有0,证明是一条合法的路径,记录不同路径的数目;否则不进行记录。

编写代码

class Solution {
    int ret;
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    int visited[20][20];
    int m, n, step=1;
public:
    int uniquePathsIII(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        int r = 0, c = 0;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(grid[i][j] == 1)
                    r=i, c=j;
                else if(grid[i][j] == 0)
                    ++step;
            }
        }
        visited[r][c] = true;
        DFS(grid, r, c, 0);
        return ret;
    }

    void DFS(vector<vector<int>>& grid, int r, int c, int cnt)
    {
        if(grid[r][c] == 2)
        {
            if(step == cnt) ++ret;
            return;
        }
        for(int i = 0; i < 4; ++i)
        {
            int x=r+dx[i], y=c+dy[i];
            if(x>=0 && x<m && y>=0 && y<n && !visited[x][y] && grid[x][y]!=-1)
            {
                visited[x][y] = true;
                DFS(grid, x, y, cnt+1);
                visited[x][y] = false;
            }
        }
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/698320.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

全彩LED显示屏可视角度分析

在当今数字化时代&#xff0c;全彩LED显示屏已成为公共场所、商业中心、体育赛事等场合传递信息与视觉震撼的重要媒介。然而&#xff0c;对于这些显示屏而言&#xff0c;一个关键的技术指标——可视角度&#xff0c;直接决定了观众能否从各个方位享受到一致且优质的视觉体验。本…

SQLserver前五讲课堂笔记

第一讲 基本内容 为什么要学习数据库系统?什么是数据库?什么是数据库系统?什么是数据库管理系统&#xff1f;本课程学什么以及学到什么程度? 重点难点 一组概念的区分&#xff1a;数据库、数据库系统和数据库管理系统熟悉表 的相关要素及术语熟悉数据库系统的构成(工作…

win10怎么截图?电脑截图的3个方法分享

win10怎么截图&#xff1f;在Windows 10操作系统中&#xff0c;截图功能不仅强大而且极其便捷。无论用户需要快速捕捉整个屏幕的内容&#xff0c;还是精确截取屏幕上的特定区域&#xff0c;它都能迅速响应并满足需求。通过内置的截图工具和快捷键&#xff0c;我们可以轻松完成各…

SwiftUI中自定义ViewModifier

在SwiftUI中&#xff0c;ViewModifier是一种强大的工具&#xff0c;用于封装和复用视图修改逻辑。通过创建自定义的ViewModifier&#xff0c;我们可以以一种干净且可维护的方式重用视图配置和样式。本文将介绍如何在SwiftUI中创建和使用自定义ViewModifier。 ViewModifier是一…

【Linux】ls命令

这个命令主要是用于显示指定工作目录下之内容&#xff08;列出目前工作目录所含的文件及子目录)。 掌握几个重点的常使用的就可以&#xff1a; ls -l # 以长格式显示当前目录中的文件和目录 ls -a # 显示当前目录中的所有文件和目录&am…

【内存管理】内存布局

ARM32位系统的内存布局图 32位操作系统的内存布局很经典&#xff0c;很多书籍都是以32位系统为例子去讲解的。32位的系统可访问的地址空间为4GB&#xff0c;用户空间为1GB ~ 3GB&#xff0c;内核空间为3GB ~ 4GB。 为什么要划分为用户空间和内核空间呢&#xff1f; 一般处理器…

BarTender 常见的使用要点

BarTender 简述 BarTender是由美国海鸥科技&#xff08;Seagull Scientific&#xff09;推出的一款条码打印软件&#xff0c;被广泛应用于标签、条形码、证卡和RFID标记的设计和打印领域。它在全球范围内拥有众多用户&#xff0c;被公认为标签打印方面的全球领先者。BarTender…

一.iOS核心动画 - 关于图层与视图

引言 Core Animation听起来会让人误以为它只是用来做动画的&#xff0c;但是事实上它是从Layer Kit库演变而来的&#xff0c;其中做动画的功能只是Core Animation特性的一小部分。 Core Animation是一个复核引起&#xff0c;它的作用就是尽可能快地组合屏幕上不同的显示内容&…

【Vue】getters

除了state之外&#xff0c;有时我们还需要从state中筛选出符合条件的一些数据&#xff0c;这些数据是依赖state的&#xff0c;此时会用到getters getters就类似于属性中的计算属性 这个getter只有获取&#xff0c;如果需要设置修改&#xff0c;还是需要经过mutations getters里…

实验四、零比特插入《计算机网络》

但凡这句话有一点用的话也不至于一点用都没有。 目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 掌握零比特插入原理及方法使用任意编程语言实现零比特插入方法。 二、实验内容 掌握零比特插入原理及方法 点对点协议 PPP&#xff08;Point-to-Point Protoco…

8.11 矢量图层线要素单一符号使用六(光栅线)

文章目录 前言光栅线&#xff08;Raster Line&#xff09;QGis设置线符号为光栅线&#xff08;Raster Line&#xff09;二次开发代码实现光栅线&#xff08;Raster Line&#xff09; 总结 前言 本章介绍矢量图层线要素单一符号中光栅线&#xff08;Raster Line&#xff09;的使…

Navicat导入json文件(json文件数据导入到MySQL表中)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Threejs-05、设置响应式画布与全屏控制。

1、自适应屏幕大小 你会发现,我们前面写好的代码,在页面尺寸发生改变的时候,并不能自适应的改变尺寸,而出现空白或者滚动条突出的情况。所以监听屏幕大小的改变,来重新设置相机的宽高比例和渲染器的尺寸大小,代码如下: // 监听画面变化,更新渲染画面 window.addEven…

删除的东西怎么恢复?5个方法,找回误删数据!

“我刚刚一不小心在电脑上误删了一些数据&#xff0c;想问问大家有什么方法可以恢复删除的东西吗&#xff1f;请帮帮我&#xff01;” 在数据时代&#xff0c;我们每天会在电脑上保存很多重要的数据&#xff0c;这些数据不仅包括我们的学习资料、工作信息&#xff0c;还有各种个…

DeepSORT(目标跟踪算法)中自由度决定卡方分布的形状

DeepSORT&#xff08;目标跟踪算法&#xff09;中自由度决定卡方分布的形状 flyfish 重要的两个点 自由度决定卡方分布的形状&#xff08;本文&#xff09; 马氏距离的平方在多维正态分布下服从自由度为 k 的卡方分布 独立的信息 在统计学中&#xff0c;独立的信息是指数据…

震撼!AI语言模型突破瓶颈,26个提示词原则引领GPT-4响应质量飙升57.7%!你的模型还在等什么?

不是模型不够强大&#xff0c;是你的提示不够精准。 当大型语言模型如ChatGPT在各领域大放异彩时&#xff0c;普通用户却对其指令设计一头雾水。这篇论文揭秘了与模型交流的秘诀&#xff0c;仅凭优化提示&#xff0c;就让GPT-4响应质量和准确性分别飙升57.7%和36.4%&#xff0…

重生奇迹mu套装掉的地点一览

1、目前只有三个地方掉套装&#xff1a;赤色要塞&#xff0c;不是100%掉&#xff0c;靠运气。卡利玛7&#xff0c;杀困顿能掉。魔炼之地&#xff0c;只有城主盟成员可以进入。 2、只有攻城城主盟可以进入的地图“魔炼之地”掉套装&#xff0c;暴率几乎为0。如果你是敏法的话&am…

C++ 判断目标文件是否被占用(独占)(附源码)

在IM软件中发起文件发送时,如果要发送的是某word文件,并且该word文件被office打开,则会提示文件正在被占用无法发送,如下所示: 那文件被占用到底是如何判断出来的呢?其实很简单,调用系统API函数CreateFile,打开该文件(OPEN_EXISTING),传入FILE_SHARE_READ共享读标记…

MySQL—多表查询—练习(2)

一、引言 接着上篇博客《 MySQL多表查询——练习&#xff08;1&#xff09;》继续完成剩下的案例需求。 二、案例 &#xff08;0&#xff09;三张表&#xff08;员工表、部门表、薪资等级表&#xff09; 员工表&#xff1a;emp 部门表&#xff1a;dept 薪资等级表&#xff1a;…

CF297C Splitting the Uniqueness 题解

CF297C Splitting the Uniqueness 题解 非常好构造题&#xff0c;使我的草稿纸旋转。 解法 我们记输入的数组为 a a a&#xff0c;需要输出的两个数组为 b , c b,c b,c&#xff08;因为当时起变量名起的&#xff09;。 考虑利用 a i a_i ai​ 互不相同的性质。 先将 a…