做的一些题目的答案和自己的一些思考

现在的AI,到底是背答案的高手,还是真正的会思考 当Deepseek用550万美元的成本,训练出能够与GPT-4o抗衡的模型的时候,就应该明白,现在的AI凭借的并非是大量耗费钱财去堆砌硬件,而是应该借助精妙的算法来充分地榨取算力。教育领域已然给出了答案:当AI能够瞬间解开奥数题的时候,有的学校就开始布置“利用AI创作春联”的作业了,重点不再仅仅是答案本身,而是操控AI的那种思路。现在的AI会使用“混合专家架构”,将知识进行拆分,在这个时候把它储存起来,就如同超市里的货架一样,分类很清楚,条理十分分明。毕竟工具再聪明,也是给人用的,不是用来把人变废的。 阅读详情

LeetCode

class Solution {
public:
    // 题目要求的接口函数
    int climbStairs(int n) {
        return helper(n); // 调用自定义函数
    }

private:
    // 自定义辅助函数(带记忆化)
    int helper(int n) {
        if(n <= 2) return n;
        return helper(n-1) + helper(n-2);
    }
};

动态规划

最大子序和
1线性 DP最大子序和LC-53状态转移与决策分析✅2
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sz = nums.size();
        int f[100005];
        f[0] = nums[0];
        int max_val = f[0];
        for(int i = 1;i<sz;i++){
            f[i] = max(nums[i],f[i-1]+nums[i]);
            max_val = max(max_val,f[i]);
        }
        return max_val;
    }
};
最小路径和
最小路径和LC-64二维DP递推✅
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
         vector<vector<int>>dp(m,vector<int>(n,0));
        dp[0][0] = grid[0][0];
        for(int i = 1;i<m;i++) dp[i][0] = dp[i-1][0] + grid[i][0];
        for(int j = 1;j<n;j++) dp[0][j] = dp[0][j-1] + grid[0][j];
        for(int i = 1;i<m;i++){
            for(int j = 1;j<n;j++){
                int x = dp[i-1][j];
                int y = dp[i][j-1];
                dp[i][j] = min(x,y)+grid[i][j];
            }
        }
    return dp[m-1][n-1];
    }
};
乘积最大子数组
乘积最大子数组LC-152状态转移变种(维护最大最小值)✅
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int sz = nums.size();
        int max_product = nums[0];
        int min_product = nums[0];
        int result = nums[0];
        for(int i = 1;i<sz;i++){
        //用临时变量存储 这样才能保证临时最小值求的是按照前i-1个数求的
        //因为这样max_product没在求临时最大值时改变
            int temp_max_product = max({nums[i],min_product*nums[i],max_product*nums[i]});
            int temp_min_product = min({nums[i],min_product*nums[i],max_product*nums[i]});
            max_product = temp_max_product;
            min_product = temp_min_product;
            result = max(max_product,result);
        }
    return result;
    }
};

由于 max_product 是当前的 max_product*nums[i] / min_product*nums[i] / nums[i] 中选的
所以即使 max_product 可能比 max_product*nums[i] / min_product*nums[i] / nums[i] 三者大
更新后的 max_product 也是 max_product*nums[i] / min_product*nums[i] / nums[i] 中的最大值
因此要有个全局变量 result来维护最大值

⭐编辑距离
编辑距离LC-72经典双序列DP✅
class Solution {
public:
    int minDistance(string word1, string word2) {
        int sz1 = word1.size();
        int sz2 = word2.size();
        vector<vector<int>> dp(sz1 + 1, vector<int>(sz2 + 1, 0));
        //初始化
        for(int i = 0;i<=sz1;i++) dp[i][0] = i;
        for(int j = 0;j<=sz2;j++) dp[0][j] = j;
        //状态转移  dp[i][j]代表word1的前i个字母要修改到和word2的前j个字母 所需的次数
        //分三个操作
        //插入 相当于再word1的第i+1位置插入和word2的第j个字母对应的字母 接下来要处理到word1的1~i和word2的1~(j-1)一样即可
        //删除 dp[i-1][j] word1的第i个删除,要考虑word1的前i-1个变化到和word2的前j个相等
        //替换 dp[i-1][j-1]
        for(int i = 1;i<=sz1;i++){
            for(int j = 1;j<=sz2;j++){
                if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
                else{
                    dp[i][j] = min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]})+1;
                }
            }
        }
        return dp[sz1][sz2];
    }
};
⭐ 导弹拦截
导弹拦截洛谷-P1020最长不升子序列+贪心优化+二分 (卡时间)
关于upper_bound和lower_bound
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int nums[N];

int main() {
    int n = 0;
    while (cin >> nums[n]) n++; // 读取输入数据

    // 第一问:最长不升子序列
    vector<int> lis;
    for (int i = 0; i < n; ++i) {
        if (lis.empty() || nums[i] <= lis.back()) {
            lis.push_back(nums[i]);
        } else {
            auto it = upper_bound(lis.begin(), lis.end(), nums[i], greater<int>());
            *it = nums[i];
        }
    }
    cout << lis.size() << endl;

    // 第二问:最长上升子序列(Dilworth定理)
    vector<int> seq;
    for (int i = 0; i < n; ++i) {
        if (seq.empty() || nums[i] > seq.back()) {
            seq.push_back(nums[i]);
        } else {
            auto it = lower_bound(seq.begin(), seq.end(), nums[i]);
            *it = nums[i];
        }
    }
    cout << seq.size();

    return 0;
}

求最长不上升子序列时
利用了贪心+二分
其中贪心策略是,

  1. 维护一个递减数组 lis。
  2. 遍历每个元素 x:
    • 若 x ≤ lis.back(),直接加入 lis。
    • 否则,找到 lis 中第一个比 x 小的位置,用 x 替换该位置的值。
  3. 最终 lis 的长度即为 LNIS 的长度。
    因为当 x ≤ lis.back() 时,LNIS 的长度不会有变化发生
    只有 x > lis.back() 时,可以将 x 添加到 lis 的末尾,此时 LNIS 的长度才会增加
    ⭐⭐⭐
  • 核心思想:让 lis 的每个位置保存该长度下最大的末尾元素
    ⭐⭐⭐
俄罗斯套娃信封问题
俄罗斯套娃信封问题LC-354二维LIS优化✅
class Solution {
public:
    int maxEnvelopes(vector<vector<int>>& envelopes) {
        // 正确排序:宽度升序,相同宽度则高度降序
        sort(envelopes.begin(), envelopes.end(), [](const vector<int>& a, const vector<int>& b) {
            if (a[0] == b[0]) return a[1] > b[1];
            return a[0] < b[0];
        });
        // 提取高度数组并寻找LIS
        vector<int> lis;
        for (const auto& env : envelopes) {
            int h = env[1];//高度
            auto it = lower_bound(lis.begin(), lis.end(), h);
            if (it == lis.end()) {
                lis.push_back(h);
            } else {
                *it = h;
            }
        }
        return lis.size();
    }
};
/*
将排序改为先按宽度升序,宽度相同按高度降序。
在构建LIS时,仅比较高度,因为宽度已经通过排序处理好了。
使用标准的LIS算法处理高度数组。
排序后的数组是按照宽度升序,高度降序,那么相同宽度的信封不会相互干扰,
因为它们的高度是降序的,这样后面遇到的高度只会更小,避免重复排序的问题
也就是说这样排序后
为  a3 a2 a1 b2 b1 c2 c1(a<b<c)
则单独看高度时为
[3 2 1] [2 1] [2 1]
找高度的LIS,每组之内至多只有一个数字在LIS中
不会有多个,因为本身每一组中高度是降序的,不会在升序序列中出现

*/
通配符匹配
通配符匹配LC-44复杂模式匹配DP✅⭐
class Solution {
public:
	bool isMatch(string s, string p) {
		int m = s.size();
		int n = p.size();
		vector<vector<int >> dp(m + 1, vector<int>(n + 1));
		dp[0][0] = true;//空匹配空
		for (int i = 1; i <= m; i++) dp[i][0] = false;
		for (int i = 1; i <= n; i++) {
			if (p[i - 1] == '*') {
				dp[0][i] = true;
			} else {
				break;
			}
		}
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= n; j++) {
				if (s[i - 1] == p[j - 1]  || p[j - 1] == '?') dp[i][j] = dp[i - 1][j - 1];
				else if (p[j - 1] == '*') {
					dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
					//略过'*'去匹配P的下一位||保留'*'的活性 匹配s的下一位
				}
			}
		}
		return dp[m][n];
	}
};

重点在于理解 dp[i][j] = dp[i-1][j]||dp[i][j-1]
这句的意思是,当 p[j-1] 为 ‘*’ 的时候,因为 ‘*’ 可以匹配 0 个或者多个字符

  • 所以当 ‘*’ 视为空时(匹配 0 个),相当于直接掠过 p 的这一位,从原先的由 s[i-1] 与 p[j-1] 是否匹配的状态转移成了现在的看 s[i-1] 和 p[j] 是否匹配的转移
  • 当 ‘*’ 视为匹配多个 s 的字符时,相当于 p[j-1] 的这个 ‘*’ 一直保持活性,固定 p 的视角在 p[j-1] == ‘*’ 这里,移动 's' 进行比较
背包问题
数字组合 (0-1背包)
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[105];
int dp[105][10005];
/*
dp[i][j]前i个数中选 恰好等于j的方案数
dp[i][j] = max(dp[i-1][j], dp[i-1][j-a[i]]+1)
前i-1个数中恰好等于j-a[i]的方案数
*/
int main(){
	cin>>n>>m;
	for(int i = 1;i<=n;i++){
		cin>>a[i];
	}
	dp[0][0] = 1;
	//前n个数 dp初始化
	for(int i = 1;i<=n;i++){
		for(int j = 0;j<=m;j++){
				dp[i][j] = dp[i-1][j];
			if(j>=a[i]){
				dp[i][j] += dp[i-1][j-a[i]];
			}
		}
	}
	cout<<dp[n][m];
	return 0;
}

定义 dp[i][j] 表示 前 i 个数中选出若干个数,和为 j 的方案数。

  • 维度解释:
    • i:前 i 个数(决策阶段)。
    • j:当前目标和(状态变量)。

1. 决策分析
对于第 i 个数 a[i],有两种选择:

  • 不选:方案数等于前 i-1 个数中和为 j 的方案数,即 dp[i-1][j]。
  • 选(仅当 j >= a[i]):方案数等于前 i-1 个数中和为 j - a[i] 的方案数,即 dp[i-1][j - a[i]]。

2. 方程形式化
d p [ i ] [ j ] = { d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − a [ i ] ] if  j ≥ a [ i ] d p [ i − 1 ] [ j ] otherwise dp[i][j] = \begin{cases} dp[i-1][j] + dp[i-1][j - a[i]] & \text{if } j \geq a[i] \\dp[i-1][j] & \text{otherwise}\end{cases} dp[i][j]={dp[i−1][j]+dp[i−1][j−a[i]]dp[i−1][j]​if j≥a[i]otherwise​

搜索

DFS && BFS
岛屿数量 (连通块问题)

相当于是图的 DFS 和 BFS

1-2搜索岛屿数量LC-200中等DFS/BFS基础(连通块问题)方向数组✅Yes, 经典的模板题
//DFS做法
class Solution {
private:
	void dfs(vector<vector<char>>& grid, int x,int y){
		int m = grid.size();
		int n = grid[0].size();
		grid[x][y] = 0;//代表访问过;
		if(x-1>=0&&grid[x-1][y] == '1') dfs(grid,x-1,y);
		if(x+1<m&&grid[x+1][y] == '1') dfs(grid,x+1,y);
		if(y-1>=0&&grid[x][y-1] == '1') dfs(grid,x,y-1);
		if(y+1<n&&grid[x][y+1] == '1') dfs(grid,x,y+1);
	}
public:
	int numIslands(vector<vector<char>>& grid) {
		int m = grid.size();
		int n = grid[0].size();
		int res = 0;
		for(int i = 0;i<m;i++){
			for(int j = 0;j<n;j++){
				{
					res++;
					dfs(grid,i,j);
				}
			}
		}
		return res;
	}
};


//BFS做法
class Solution {
public:
	int numIslands(vector<vector<char>>& grid) {
		int m = grid.size();
		if(!m) return 0;
		int n = grid[0].size();
		//存放坐标
		queue <pair<int,int>> adj;
		int res = 0;
		for(int i = 0;i<m;i++){
			for(int j = 0;j<n;j++){
				if(grid[i][j] == '1'){
					res ++ ;
					adj.push({i,j});
					while(!adj.empty()){
						//获取队列中首元素的坐标后输出
						auto rc = adj.front();
						adj.pop();
						int r = rc.first;
						int c = rc.second;
						grid[r][c] == '0';
						if(r-1>=0 && grid[r-1][c] == '1'){
							adj.push({r-1,c});
							grid[r-1][c] = '0';
						}
						if(c-1>=0 && grid[r][c-1] == '1'){
							adj.push({r,c-1});
							grid[r][c-1] = '0';
						}
						if(r+1<m && grid[r+1][c] == '1'){
							adj.push({r+1,c});
							grid[r+1][c] = 0;
						}
						if(c+1<n && grid[r][c+1] == '1'){
							adj.push({r,c+1});
							grid[r][c+1] = '0';
						}
					}
				}
			}
		}
		return res;
	}
};
二叉树的层序遍历(树的BFS遍历)

相当于是树的 BFS

二叉树的层序遍历LC-102中等BFS模板(队列应用)✅
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(!root) return res;

        queue<TreeNode*> q;
        q.push(root);

        while(!q.empty()) {
            int levelSize = q.size();
            vector<int> levelVal;
            
            for(int i = 0; i < levelSize; ++i) {
                TreeNode* tmp = q.front();
                q.pop();
                levelVal.push_back(tmp->val);
                
                // 修正点:判断子节点存在才入队
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
            }
            
            res.push_back(levelVal);
        }
        return res;
    }
};

初始化队列,如果根节点存在则入队。
然后,当队列不为空时:

  • 获取当前层的节点数量size = q.size()
  • 创建一个临时vector level
  • 循环size次:
    • 取出队列前端节点
    • 将节点值加入level
    • 如果有左子节点,入队
    • 如果有右子节点,入队
  • 将level添加到res中
    这样就能正确分层处理节点,并且避免越界问题。
离开中山路(BFS求图中最短路径)
离开中山路洛谷
P1706
简单BFS最短路径基础✅
#include <bits/stdc++.h>
using namespace std;

int n, st_x, st_y, ed_x, ed_y;
char grid[1005][1005];
int dist[1005][1005]; // 距离数组兼做访问标记

int main() {
	cin >> n;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			cin >> grid[i][j];

	cin >> st_x >> st_y >> ed_x >> ed_y;

	// 检查起点合法性
	if (grid[st_x][st_y] != '0') {
		cout << -1;
		return 0;
	}
	queue<pair<int, int >> q;
	memset(dist, -1, sizeof(dist));//距离一开始都设置为不可达

	q.push({st_x, st_y});//起始点
	dist[st_x][st_y] = 0;//起点到起点的距离为0

	// 四方向数组
	int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
	while(!q.empty()) {
		auto[x, y] = q.front();
		q.pop();
		if(x == ed_x && y == ed_y) {
			cout << dist[x][y];
			return 0;
		}
		for(auto [dx, dy] : dirs) {
			int nx = x+dx;
			int ny = y+dy;
			if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&//在范围内
				grid[nx][ny] == '0'&&//是路
				dist[nx][ny]==-1//未访问过
				){
				dist[nx][ny] = dist[x][y]+1;
				q.push({nx,ny});
			}
		}
	}

	cout << -1; //不可达
	return 0;
}
记忆化搜索:斐波那契数
记忆化搜索示例:斐波那契数LC-509简单记忆化搜索入门
class Solution {
private:
	int dfs(int n ,vector<int>& memo){
		if(memo[n] != -1) return memo[n];
		if(n<=1){
			memo[n] = n;
			return n;
		}
		memo[n] = dfs(n-1,memo)+dfs(n-2,memo);
		return memo[n];
	}
public:
	int fib(int n) {
		vector<int>memo(n+2,-1);
		return dfs(n,memo);
	}
};
迷宫问题 (求路径条数回溯算法)
迷宫问题洛谷 P1605普及-DFS回溯(路径搜索)
#include<bits/stdc++.h>
using namespace std;
int n,m,t,st_x,st_y,ed_x,ed_y;
int grid[6][6];//迷宫
int res;
//0是路 1是障碍
void dfs(int x,int y){
	if(x == ed_x&&y==ed_y){
		res++;
		return ;
	}//到达终点
	if(grid[x][y]!=0){
		return ;//撞 障碍物/走过的部分 了
	}
	if(x<1||y<1||x>n||y>m){
		return ;//撞墙
	}
	grid[x][y] = 1;//标记走过了
	dfs(x+1,y);
	dfs(x-1,y);
	dfs(x,y+1);
	dfs(x,y-1);
	grid[x][y] = 0;
}
int main(){
	//长n宽m,t个障碍
	cin>>n>>m>>t;
	//起点 终点坐标
	cin>>st_x>>st_y>>ed_x>>ed_y;
	for(int i = 0;i<t;i++){
		int x,y;
		cin>>x>>y;
		grid[x][y] = 2;//代表障碍
	}
	//DFS
	if(grid[ed_x][ed_y]!=0){
		cout<<0;
		return 0;
	}
	dfs(st_x,st_y);
	cout<<res;
	return 0;
	
	return 0;
}
单词搜索 (DFS判断有无正确路线)
单词搜索LC-79中等DFS回溯(二维矩阵搜索)
class Solution {
private:
	bool found = false;
	void dfs(int x,int y,int& res,vector<vector<char>>& board,string word,vector<vector<int>>&vis){
		if(found) return ;//找到了 return
		int m = board.size();
		int n = board[0].size();
		if(res == word.size()-1){
			found = true;
			return ;
		}
		vis[x][y] = 1;
		res ++;
		if(x-1>=0&&board[x-1][y] == word[res]&&vis[x-1][y]!=1){
			dfs(x-1,y,res,board,word,vis);
		}
		if(y-1>=0&&board[x][y-1] == word[res]&&vis[x][y-1]!=1){
			dfs(x,y-1,res,board,word,vis);
		}
		if(x+1<m&&board[x+1][y] == word[res]&&vis[x+1][y]!=1){
			dfs(x+1,y,res,board,word,vis);
		}
		if(y+1<n&&board[x][y+1] == word[res]&&vis[x][y+1]!=1){
			dfs(x,y+1,res,board,word,vis);
		}
		res -- ;
		vis[x][y] = 0;
	}
public:
	bool exist(vector<vector<char>>& board, string word) {
		int m = board.size();
		int n = board[0].size();
		//选出和word第一个字符一样的点的位置
		//存放在rc中
		vector<pair<int,int>>rc;
		for(int i = 0;i<m;i++){
			for(int j = 0;j<n;j++){
				if(board[i][j] == word[0]){
					rc.push_back({i,j});
				}
			}
		}
		
		//遍历这几个和word[0]一样的点,以他们为起点 进行回溯
		for(auto p : rc){
			int res = 0;
			int x = p.first;
			int y = p.second;
			vector<vector<int>>vis(m,vector<int>(n,0));
			dfs(x,y,res,board,word,vis);
			if(found){
				return true;
			}
		}
		return false;
	}
};

在用 dfs 时,因为要用到递归,所以莫忘记写递归结束的条件
该题是 res == word.size() - 1
不要把条件写在 dfs 函数外面(比如写在主函数中)
因为这样的话,dfs 就会一直循环,进行多次重复计算
并且该题目是只要有一种结果就是 true,所以可以用 found 变量,这样可以防止某一次已经找到了最终结果但仍重复计算的事情发生

滑雪(DFS记忆化搜索寻找最长路径)
滑雪洛谷 P1434普及+/提高记忆化搜索(DFS+DP)✅
#include <bits/stdc++.h>
using namespace std;
int m , n;
int grid[105][105];
int dp[105][105];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int dfs(int x,int y){
	if(dp[x][y] != 0) return dp[x][y];
	dp[x][y] = 1;//每次到达这个点都要初始化
	for(int i = 0;i<4;i++){
		int xx = x+dx[i];
		int yy = y+dy[i];
		if(xx>=1&&xx<=m&&yy>=1&&yy<=n&&grid[xx][yy]<grid[x][y]){
			dfs(xx,yy);
			dp[x][y] = max(dp[x][y],dp[xx][yy]+1);
		}
	}
	return dp[x][y];
}
int main(){
	//m行n列
	cin>>m>>n;
	for(int i = 1;i<=m;i++){
		for(int j = 1;j<=n;j++){
			cin>>grid[i][j];
		}
	}
	//
	int ans = 0;
	for(int i = 1;i<=m;i++){
		for(int j =1;j<=n;j++){
			ans = max(ans,dfs(i,j));
		}
	}
	cout<<ans;
	return 0;
}

dp[x][y] 表示 从坐标 (x, y) 出发,能滑行的最长路径的长度。

状态转移方程:
d p [ x ] [ y ] = max ⁡ ( x x , y y ) ∈ neighbors grid [ x x ] [ y y ] < grid [ x ] [ y ] ( d p [ x x ] [ y y ] + 1 ) dp[x][y] = \max_{\substack{(xx, yy) \in \text{neighbors} \\ \text{grid}[xx][yy] < \text{grid}[x][y]}} \left ( dp[xx][yy] + 1 \right) dp[x][y]=max(xx,yy)∈neighborsgrid[xx][yy]<grid[x][y]​​(dp[xx][yy]+1)

⭐滑动谜题(BFS+状态压缩)
滑动谜题LC-773困难BFS+回溯+记忆化搜索+DP✅用了 BFS +状态压缩2
class Solution {
public:
	int slidingPuzzle(vector<vector<int>>& board) {
		string target= "123450";
		string start;
		//board拼接为start字符串
		for(int i = 0;i<2;i++){
			for(int j = 0;j<3;j++){
				start +=(board[i][j] + '0');
			}
		}
		//BFS初始化
		queue<pair<string,int>>q;
		vector<vector<int>>dirs = {{0,1},{0,-1},{1,0},{-1,0}};
		unordered_set<string>vis;//若某个状态存在 则vis.count(state) != 0
		//状态转移逻辑
		q.push({start,0});//start  0步
		vis.insert(start);//start  已访问
		while(!q.empty()){
			//取出来第一个元素
			auto [state,steps] = q.front();
			q.pop();//出队 勿忘
			//破壳
			if(state == target) return steps;
			//找0的位置
			int pos = state.find('0');
			//0所在位置的坐标
			int x = pos/3;
			int y = pos%3;
			for(int i = 0;i<4;i++){
				int nx = x+dirs[i][0];
				int ny = y+dirs[i][1];
				if(nx>=0&&ny>=0&&nx<2&&ny<3){
					string newState = state;
					int newPos = nx*3+ny;
					swap(newState[newPos],newState[pos]);
					//如果没被访问过
					if(!vis.count(newState)){
						vis.insert(newState);
						q.push({newState,steps+1});
					}
				}
			}
		}
		return -1;
	}
};

1. 状态压缩
将二维数组转换为字符串,例如:

初始状态 [[1,2,3],[4,0,5]] → 字符串 "123405"
目标状态 [[1,2,3],[4,5,0]] → 字符串 "123450"

2. BFS初始化

  • 队列:存储待处理的状态和当前步数。
  • 哈希集合:记录已访问状态,避免重复。
  • 方向数组:定义 0 的移动方向(上下左右)。
    3. 状态转移逻辑
  1. 找到 0 的位置:通过字符串的 find 方法。
  2. 转换为二维坐标:计算行 x = pos / 3,列 y = pos % 3。
  3. 尝试四个方向移动:
    • 计算新坐标 (nx, ny)。
    • 检查是否越界(行范围 0~1,列范围 0~2)。
  4. 生成新状态:交换 0 和新位置的字符。
    4. 终止条件
    当前状态等于目标状态时,返回步数。

并查集

765. 情侣牵手

我们不关心具体交换过程,只关心“最终配对结果”。
把每对情侣看作一个编号(情侣对编号 = person_id / 2),那么:

  • 每两个相邻的人(row[i], row[i+1])分别属于两个情侣编号。

  • 如果这两个编号不是同一个,就表示“当前配错了位置”,我们就将这两个情侣编号合并成一个集合。
    最终我们会得到若干个连通块(集合),每个块内的人只能通过内部交换来变正确。

  • 每个集合内部,需要的最少交换次数是:集合大小 - 1

  • 所以所有集合最少交换次数总和是:总对数 - 集合数量

class Solution {
private:
    int fa[32];
    int sets;
    int find(int x){
        if(fa[x] == x) return x;
        int root = find(fa[x]);//递归找最深层次的根节点,找每次递归点的父节点的父节点的…
        fa[x] = root;//扁平化处理
        return root;

    }
    void unite(int x,int y){
        if(find(x) != find(y)){
            int root_x = find(x);
            int root_y = find(y);
            fa[root_x] = root_y;//x挂在y上
            sets -- ;
        }
    }
public:

    int minSwapsCouples(vector<int>& row) {
        int sz = row.size();
        int m = sz/2;
        sets = sz/2;//集合个数
        for(int i = 0;i<m;i++) fa[i] = i;//该题是对情侣编号进行操作的
        for(int i = 0;i<sz;i+=2){
                unite(row[i]/2,row[i+1]/2);//合并的是两者的情侣编号
        }
        return m - sets;
    }
};
839. 相似字符串组

我们定义“相似”具有传递性:
如果 A ~ B 且 B ~ C,则 A ~ C

  • 每个字符串视为图中的一个点。
  • 如果两个字符串“相似”,就在它们之间连一条边。
  • 那么整个问题就变成了:图中有多少个连通块(也就是「相似字符串组」)。
class Solution {
private:
	int fa[302];
	int sets ;
	int find(int x){
		if(x == fa[x]) return x;
		int root = find(fa[x]);
		fa[x] = root;//扁平化
		return root;
	}
	void unite(int x,int y){
		int root_x = find(x);
		int root_y = find(y);
		if(root_x != root_y){
			fa[root_x] = root_y;
			sets -- ;
		}
	}
	bool isSimilarStr(string s1,string s2){
		int m = s1.size();
		int diff = 0;
		for(int i = 0;i<m && diff<3;i++){
			if(s1[i] != s2[i]){
				diff ++;
			}
		}
		if(diff == 0 || diff == 2) return true;
		else return false;
		
	}
public:
	int numSimilarGroups(vector<string>& strs) {
		int n = strs.size();//n个单词
		sets = n;//sets个集合
		for(int i = 0;i<n;i++) fa[i] = i;//每个单词指向自己
		for(int i = 0;i<n;i++){
			for(int j = i+1;j<n;j++){
				if(isSimilarStr(strs[i],strs[j])){
					unite(i,j);
				}
			}
		}
		return sets;
	}
};
947. 移除最多的同行或同列石头

如果两个石头在同一行或同一列,那么我们可以通过某种顺序把它们全部“连通”起来(因为移除一个不会影响另一个的“可达性”)。

所以我们可以将这些石头抽象为图上的点,只要两个石头满足“同行或同列”,就认为它们之间有一条边,构成一个 连通块。

一个连通块里,总是可以移除 块中石头数 - 1 个石头(留一个不动就行)。

class Solution {
private:
	int fa[1005];
	int sets;
	int find(int x){
		if(x == fa[x]) return x;
		int root = find(fa[x]);
		fa[x] = root;//扁平化处理
		return root;
	}
	void unite(int x,int y){
		int root_x = find(x);
		int root_y = find(y);
		if(find(x) != find(y)){
			fa[root_x] = root_y;
			sets -- ;
		}
	}
public:
	int removeStones(vector<vector<int>>& stones) {
		map<int, int> firstRow; // 列,石头序号
		map<int, int> firstCol; // 行,石头序号
		int n = stones.size();
		iota(fa,fa+n+1,0);
		sets = n;
		// 数据前置处理
		for (int i = 0; i < n; i++) {
			int col = stones[i][0];
			int row = stones[i][1];
			if (firstCol.find(col) == firstCol.end()) {
				firstCol.insert({col, i});
			} else {
				unite(i, firstCol[col]); // 合并石头
			}
			if (firstRow.find(row) == firstRow.end()) {
				firstRow.insert({row, i});
			} else {
				unite(i, firstRow[row]); // 合并石头
			}
		}
		return n - sets;
	}
};
2092. 找出知晓秘密的所有专家

这题的做法是:
首先专家 0 和 firstPerson 知道秘密,将他们俩合并
然后后续的会议按照时间戳排序
对于相同的时间内的会议做处理(筛选相同时间的操作看代码,很妙)
在这个时间内,一个个的按照并查集的方式分组,并且更新是否知晓秘密的信息
每一段相同的时间完成后,再重新遍历一遍会议,把无意义的会议造成的集合的合并撤销掉
最后按照 secret[find (x)]来得到答案

class Solution {
private:
	int fa[100005];
	bool secret[100005];
	int find(int x){
		if(x == fa[x]) return x;
		int root = find(fa[x]);
		fa[x] = root;//扁平化
		return root;
	}
	void unite(int x,int y){
		int fx = find(x);
		int fy = find(y);
		if(fx != fy){
			fa[fx] = fy;//x挂在y上
			secret[fy] |= secret[fx];//更新fy的信息
		}
	}
public:
	vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
		iota(fa,fa+n,0);//每个人的父节点
		for(int i = 0;i<n;i++) secret[i] = false;
		secret[0] = true;
		secret[firstPerson] = true;//知道秘密
		//时间排序
		sort(meetings.begin(),meetings.end(),[](const vector<int>& a,const vector<int>& b){
			return a[2] < b[2];
		});
		//按照时刻做
		int m = meetings.size();
		for(int l = 0;l<m ;){
			int r = l;
			while(r+1<m && meetings[r+1][2] == meetings[l][2]){
				r ++;//找到右边界
			}
			for(int i = l;i<=r;i++){
				unite(meetings[i][0],meetings[i][1]);//合并此时的会议专家
			}
			//撤销选择
			for(int i = l;i<=r;i++){
				int a = meetings[i][0];
				int b = meetings[i][1];
				if(!secret[find(a)]){
					fa[a] = a;
				}
				if(!secret[find(b)]){
					fa[b] = b;
				}
			}
			l = r + 1;
		}
		//计算答案
		vector<int>ans;
		for(int i = 0;i<n;i++){
			if(secret[find(i)]){
				ans.push_back(i);
			}
		}
		return ans;
		
	}
};
2421. 好路径的数目

该题目讲解
这题的做法是,除了开 fa 数组存放父节点外,还开一个 maxcnt 标记数组
然后按照边的两端的节点中的值更大的那个值升序(从小到大)排序
先处理边最小(也就是所有边中,边的顶点值的最大值最小的)的,后续依次遍历
把每次遍历到的边的两个点的所在的两个集合进行合并 (在同一个集合无需合并)
对于合并:要选择集合的代表顶点值更大的那个点做两个集合所合并成的集团的代表节点,然后若合并前的两个集合的代表节点的最大值相同,且数量为 m 和 n (由 cntmax[fa[x]]和 cntmax[fa[y]] 得到) ,则说明这两个集合可以构成的好路径的个数为 (m×n),因为 m 和 n 都是集合内节点的最大节点值,到另一个集合的最大节点的路径上,肯定没有比首尾节点(也就是这里的最大节点)还大的值了,所以每两个节点形成一条好路径。两两组合就是 m×n
最终的答案再加上每个节点到自身的路径(也是好路径)

class Solution {
private:
	//const int MAXN = 30010;
	int fa[30010];//father数组
	int maxcnt[30010];//集团中的最大值出现次数
	void build(int n){//节点个数
		for(int i = 0;i<n;i++){
			fa[i] = i;//指向自身
			maxcnt[i] = 1;//初始都为1
		}
	}
	int find(int x){
		if(x == fa[x]) return x;
		int root = find(fa[x]);//递归找root
		fa[x] = root;//扁平化
		return root;
	}
	int unite(int x,int y,vector<int>& vals){//返回好路径的条数
		int path = 0;
		int fx = find(x);
		int fy = find(y);//既是集团的代表节点 也是集团中出现的最大的节点值的下标
		if(vals[fx] > vals[fy]){//值小的合并在值大的集团上
			fa[fy] = fx;
		}else if(vals[fx] < vals[fy]){
			fa[fx] = fy;
		}else{//怎么合并无所谓 但是maxcnt要根据合并方法计数
			path = maxcnt[fx]*maxcnt[fy];
			fa[fx] = fy;//x合并在y上
			maxcnt[fy] += maxcnt[fx];
		}
		return path;
	}
	
public:
	int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
		int n = vals.size();
		build(n);
		sort(edges.begin(),edges.end(),[&](const vector<int>& a,const vector<int>&b){//按照边的最大节点的大小排序
			int val_a = max(vals[a[0]],vals[a[1]]);
			int val_b = max(vals[b[0]],vals[b[1]]);
			return val_a < val_b;//从小到大排序
		});
		//并查集处理
		int ans = n;
		for(auto edge : edges){
			ans += unite(edge[0],edge[1],vals);
		}
		return ans;
	}
};

小题

罗马数字转整数 (哈希表映射)
★小题罗马数字转整数LC-13哈希表映射✅
class Solution {
public:
	int romanToInt(string s) {
		unordered_map<char, int> roman = {
			{'I',1}, {'V',5}, {'X',10}, {'L',50},
			{'C',100}, {'D',500}, {'M',1000}
		};
		
		int total = 0;
		for(int i=0; i<s.size(); ++i){
			// 当前字符值 < 后一个字符值 → 减去当前值
			if(i+1 < s.size() && roman[s[i]] < roman[s[i+1]]){
				total -= roman[s[i]];
			} else {
				total += roman[s[i]];
			}
		}
		return total;
	}
};

婚配问题 (GS 算法)
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
int main() {
	int x;
	cin >> x;
	bool first = true;
	while (x--) {
		if (!first) cout << endl;
		first = false;
		int n;
		cin >> n;
		vector<char> male_names(n), female_names(n);
		for (int i = 0; i < n; ++i) cin >> male_names[i];//输入男性名字
		for (int i = 0; i < n; ++i) cin >> female_names[i];//输入女性名字
		//男性名字 女性名字 映射序号
		map<char, int>male_map, female_map;
		for (int i = 0; i < n; i++) {
			male_map[male_names[i]] = i;//'a' -> 0
			female_map[female_names[i]] = i;//'A' -> 0
		}
		//=====男性偏好索引列表=====
		vector<vector<int> > male_prefs(n); //存储偏好索引
		for(int i = 0; i<n; i++) {
			string line;
			cin >> line;
			//此行对应的男性名称
			char c = line[0];
			//喜欢的那几个提取出来
			string line_male_prefs = line.substr(2);
			int male_index = male_map[c];//当前行的男性序号
			for (int j = 0; j < line_male_prefs.size(); ++j) {  // 修改为传统循环
				char x = line_male_prefs[j];
				int female_index = female_map[x];//当前男性喜欢的每个女性的序号
				male_prefs[male_index].push_back(female_index);
			}
		}
		//=====女性偏好索引列表====
		vector<vector<int> > female_prefs(n); //同上
		vector<vector<int> > female_rank(n, vector<int>(n)); //存储女性对男性的排名
		for (int i = 0; i < n; i++) {
			string line ;
			cin >> line;
			//此行对应的女性名字
			char c = line[0];
			//提取喜欢的人的序号
			string line_female_prefs = line.substr(2);
			int female_index = female_map[c];//当前行的女性序号
			for (int j = 0; j < line_female_prefs.size(); ++j) {  // 修改为传统循环
				char x = line_female_prefs[j];
				int male_index = male_map[x];//当前行女性喜欢的男性的序号的映射
				female_prefs[female_index].push_back(male_index);//喜欢的每个女性push进去
			}
			//反向数组 存储女性对男性的喜欢程度排名,用于下面的配偶调换
			for (int j = 0; j < n; j++) {
				int m = female_prefs[female_index][j];
				female_rank[female_index][m] = j;
			}
		}
		//=====输入的数据处理完毕=====
		/*
		a:BAC
		b:BAC
		c:ACB
		A:acb
		B:bac
		C:cab
		则
		male_prefs为   [[1 0 2],[1 0 2],[0 2 1]]
		female_prefs为 [[0 2 1],[1 0 2],[2 0 1]]
		frmale_prefs[0][2] = 1
		0号女第(2+1)喜欢的男性是1号男
		==>
		female_rank[0][1] = 2;
		0号女对1号男的喜欢顺序是第(2+1)
		*/
		//=====开始GS算法========
		vector<int> wife(n, -1); // wife[m] = 男性m当前匹配的女性索引
		vector<int> husband(n, -1); // husband[f] = 女性f当前匹配的男性索引
		stack<int> q; // 存储当前单身的男性
		for (int i = 0; i < n; i++) q.push(i); // 初始所有男性入栈
		while (!q.empty()) {
			int cur_index = q.top();//当前未婚配男性
			q.pop();
			//如果当前男性没有配偶,对于喜欢列表的女性依次匹配
			for (int k = 0; k < male_prefs[cur_index].size(); ++k) {  // 修改为传统循环
				int p = male_prefs[cur_index][k];
				if (wife[cur_index] != -1) break; // 已匹配则跳过
				
				if (husband[p] == -1) {
					husband[p] = cur_index;//男性找到配偶
					wife[cur_index] = p;//女性找到配偶
					break;//退出循环
				} else if (husband[p] != -1) { //当前女性有配偶
					int this_woman_husband = husband[p];
					//p对cur_index对应的男的喜欢程度比原配更大,则换
					//这是排名 越小越喜欢
					if (female_rank[p][cur_index] < female_rank[p][this_woman_husband]) {
						//当前匹配成功
						husband[p] = cur_index;
						wife[cur_index] = p;
						//原配偶变为单身
						wife[this_woman_husband] = -1;
						//入单身栈
						q.push(this_woman_husband);
						break;
					} else {
						//p对cur_index喜欢程度更小
						continue;
					}
				}
			}
		}
		//========== 按字典序输出结果 ==========
		vector<char> sorted_males = male_names;
		sort(sorted_males.begin(), sorted_males.end()); // 按字母顺序排序
		
		for (int i = 0; i < sorted_males.size(); ++i) {  // 修改为传统循环
			char c = sorted_males[i];
			int m = male_map[c];         // 获取男性索引
			int f = wife[m];             // 获取匹配的女性索引
			cout << c << " " << female_names[f] << endl;
		}
		
	}
	return 0;
}

[转转转]面试常见逻辑推理题目及答案整理 程序员面试喜欢考察应聘者的逻辑思考能力,但是存在一个弊端就是由于题目有限有些应聘者之前接触过被考察的题目就可以很流畅的回答出来,而没接触过的应聘者即使有相同的逻辑推理能力也很难流畅的表达出来。这样显得这个环节不太公平,但是我们只能通过增强自身的经验来克服这种情况。下面是我收集整理的一些逻辑推理类型的题目: 经典面试智力题200+题和解答中有更多类似的逻辑推理题目,感兴趣的同学可以看一下,我这里只列举常见的逻辑题目。 1. 1000个瓶子里有一瓶毒药,老鼠喝了毒药之后一天后死亡, 一次可以喝多瓶毒药,问检 阅读详情

相关推荐

数据库原理习题答案的正确打开方式:从看懂到会做

数据库系统是现代计算机应用的核心基础,数据库原理课程正是理解数据组织、关系模型、SQL查询与事务处理的关键。很多人刷完习题答案却不会做题,根源在于把答案当结果而非思考工具。真正有效的学习路径是:先独立作答,再对照解析复盘差异,最后通过限时训练和错题闭环把“看懂”变成“会做”。尤其在关系代数与SQL的相互转换、函数依赖与范式判定、事务ACID特性与并发控制等高频考点中,只有理解底层原理并将抽象概念映射到具体场景,才能应对灵活多变的题目。本文从习题答案的使用方法出发,结合数据库原理的核心知识框架,给出从刷题到掌

weixin_31155097的博客 291

算法学习总结之二分答案

本文介绍了二分答案算法的基本概念和应用。文章指出二分答案通常包含二分过程和check函数两个部分,并给出了通用模板代码。作者分享了发现的一些规律:二分题常涉及n和m两个变量,且可能用于优化时间相关或其他算法效率问题。最后以NOIP2011的"聪明的质监员"为例,展示了二分答案的实际应用。文章适合初学者了解二分答案的基本思路和实现方法。

flyingpigwb的博客 539

FPGA之串口收发字符串之(四)——串口屏USART_HMI介绍

之前对串口各模块的设计都做了相关介绍。这里介绍串口屏的相关知识。 本次项目使用的串口屏型号是陶晶驰串口屏TJC3224T024_011,这个型号的串口屏的资料在官网可以找到。本文抛转引玉,简单介绍以便在本工程中更好的应用。 下图是该串口屏的实物图: 一般地,使用单片机或者嵌入式MCU控制串口屏,都会用到串口,同样地,在FPGA中实现也是类似,不过稍微复杂,具体代码设计过程中有以下问题需要...

隔壁old余的博客 7494

leetcode刷题方法&路径

一开始刷题的时候不能够随便找个题就来做,应该一段时间专门突击某个专题,如“链表”、“二叉树”等。在刷题的过程中应该自己首先想一想,不要一没有思路就去网上找(这样刷题没有效果),自己思考半天试了一试还是做不出来就去百度。做过的题应该做笔记,反复看就跟高中做题一样,有错题本,反复看才有效果。

weixin_44163570的博客 1056

保姆级教程:在Ubuntu 20.04上搞定PX4飞控与T265的视觉定位(附避坑指南)

本文提供在Ubuntu 20.04上配置PX4飞控与T265视觉定位系统的详细教程,涵盖驱动安装、ROS与MAVROS桥接、PX4参数调优及故障排查。通过实测验证的步骤和避坑指南,帮助开发者实现厘米级精度的视觉定位,特别适合室内无人机应用。

weixin_29038155的博客 248

对称加密中GCM和CBC俩种加密模式的区别

**CBC(Cipher Block Chaining)** 和 **GCM(Galois/Counter Mode)** 是两种常见的对称加密模式。它们的主要区别体现在加密方式、性能和安全性上。

闲人 1107

【组合数学】EDU143 D. Triangle Coloring

大差不差,但是缺了一种情况:等腰三角形的时候。总方案数=大方案数*小方案数。

weixin_62528401的博客 176

TI AWR1642实战指南:CCS调试mmWave Demo Visualizer全流程解析

本文详细解析了TI AWR1642开发板的CCS调试流程,重点介绍了mmWave Demo Visualizer的使用方法。从环境准备、版本确认到bin文件烧录、CCS工程配置,再到调试启动与结果验证,提供了全流程的实战指南,帮助开发者快速掌握AWR1642的调试技巧,避免常见错误。

weixin_30790841的博客 111

二分答案法及例题

二分答案法以及例题

2301_80186482的博客 1559

拉普拉斯矩阵

1、预备知识 拉普拉斯矩阵定义为:L=D-W。其中,D为度矩阵,W为权重矩阵。 (1)D是对角矩阵,对角线上的元素时节点的度,即所有与该节点相关联的边的权重之和;对角线以外的元素为0。有向图的对角矩阵分为 出度矩阵 和 入度矩阵。 图1.1 无向图中的度矩阵 (2)W在无向图中是对称矩阵,在有向图中是非对称矩阵。 ...

zzhe 1万+

【NLP】文献翻译4——CH-SIMS:中文多模态情感分析数据集与细粒度的模态注释

CH-SIMS: A Chinese Multimodal Sentiment Analysis Dataset with Fine-grained Annotations of Modality摘要1. 介绍2. 相关工作2.1 多模态数据集2.2 多模态情感分析2.3 多任务学习3. CH-SIMS 数据集3.1 数据获取3.2 标注3.3 特征提取4. 多模式多任务学习框架4.1 单模态子网4.2 特征融合网络4.3 优化目标5. 实验5.1 基准5.2 实验的细节5.3 结果和讨论5.3.1 与

YoungSeng's Blog 1万+

做一个保持学习和思考的人

     今天有幸拜读了牛人刘未鹏《为什么你应该(从现在开始就)写博客》,很是有感觉。文章中提到的关于价值博客以及让自己成为持续学习和思考的人这两点,极大剖析了写博客的真正价值取向,也深刻让自己感到愧疚。     回想自己近几年来的学习生涯,不禁感伤,感伤自己在学习方面上较匮乏了思考,助长了停止思考问题的惰性。而更多的是跟着别人走,跟着书本走。当然绝大一方面是因为自己涉猎范围很窄,没有花更多时

Kasmile的专栏 1539

innovus:给channel加soft blockage

dbGet [dbGet top.fplan.pBlkgs.name finishfp_place_blkg_* -p].boxes就可以获得channel坐标。意思是给30um以下的channel加soft blk,至于channel的坐标,通过抓取该soft blk去获取,比较容易。工具自己加入的placement blockage命名上叫finishfp_place_blkg_*ICC2中有给channel自动加soft blockage的命令,相应的innovus也有类似的命令,我们可以使用。

m0_61544122的博客 480

数据结构浙江大学 全部思考题+每周练习答案(已完结)

MOOC上浙江大学陈越和何钦铭老师的数据结构课程很不错,通俗易懂,每周习题还都有点挑战性,这里打算将所有的题进行一下汇总。

Dezeming的博客 4万+

使用conda环境python3.13和python3.12下安装vllm过程记录

使用conda环境python3.13和python3.12下安装vllm过程记录

没刮胡子的程序员专栏 885

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

思考快与慢

本文章全部内容参考于。

weixin_55717019的博客 1127

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

电子工程师硬件工程师笔试题目及参考答案集锦

电子工程师硬件工程师笔试题目及参考答案集锦 去发现同类优质开源项目:https://gitcode.com/ 简介 本资源包含了一系列专为电子工程师和硬件工程师准备的笔试题目,并附有详细的参考答案。这些题目旨在帮助求职者在面试过程中更好地检验自己的技术能力和知识水平。 背景 作者曾因面试一家大型公司时笔试失误,深感挫折。经过深入分析和资料搜集,意识到笔试对于求职成功的重要性。因此,本资源整理了一系...

gitblog_06739的博客 493

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Leetcode刷题指南 附JAVA版答案/题解

Leetcode JAVA 题解: https://github.com/mJackie/leetcode 自己日常刷题经过是这样的: 拿到题目,看一眼Difficulty,然后自己思考一下解题思路。如果解不出来,就记下在哪里卡住了,难点在哪。 如果对应的题目有Solution,就看Solution,没有的话就点Discuss,按Most Votes排序,看排名最高的解法。 对比一下自己的解法...

JackieLiu's Blog 1万+

二分答案的思考

今天做完的了洛谷的二分答案的提单,感触颇深,就此写一写。 二分答案是什么呢? 先思考一个问题,二分究竟它的本质是用来干嘛的? 是用来查找的。 例如:一个有序数组,若要找到一个数,就去二分,logn次后找到一个数。 这就是二分的本质,逐步去筛出答案的位置。这是二分的本质,二分答案便在此基础上建立起来。 如果你知道某道题的答案是个唯一确定的整数,而且范围在1~n之间,那么我们可不可以用二分呢?当然可以。 那么我们将边界设置为1~n,然后不断缩小 ...

weixin_51504483的博客 160

MATLAB程序设计教程 第3版 第一章实验指导、思考练习答案(个人版)

MATLAB程序设计教程 第3版,刘卫国编,北京:中国水利水电出版社 第一章实验指导、思考练习答案(个人版)

Jay17的博客 3421

用Cena评测答案提交类题目的另类方法

    这几天组织了几次省选模拟赛,遇到了答案提交类的题目和交互式的题目。我一直使用Cena进行评测,现在希望把这两种类型的题目方便地加入Cena的评测结果中。交互式的题目使用Cena评测非常简单,只需要在库函数运行时输出一个以得分情况为内容的文件作为选手输出即可(http://www.matrix67.com/blog/article.asp?id=179)。但答案提交类的题目却遇

matrix67的专栏 1589

《算法导论》英文版前言To the teacher第4段研习录:有答案不让用

所以depart from sp.表示“离开某地”,而depart for sp.表示“为某地而离开”,就是“去往某地”。另外,前面一共只有两个版本,个人感觉用“前几版”好像没有必要,于是老金自作主张用了“前两版”,不知道这样做是不是有违背原文之嫌。那少年脑中一定会泛起个问号,他多久会被打一次?“更新”这个词也用的不对,更新是除旧换新,而文中指的是为还没有答案的题目增加答案,是“补充”而非“更新”。直译为“检查这个网站”,但中文没有这么说的,应译为“查看这个网站”,老金更俗一点,译为“看下这个网站”。

jjmhx的专栏 2060

《机器学习》西瓜书课后习题答案第十章 10.2

《机器学习》西瓜书课后习题10.2答案整理分享

qq_49597570的博客 1123

各大公司模数电面试题目及答案

各大公司模数电面试题目及答案 去发现同类优质开源项目:https://gitcode.com/ 资源简介 本仓库提供了一份名为“各个大公司模数电面试题目”的资源文件,该文件包含了多个知名公司模数电相关的面试题目,并附有详细的答案。这些题目和答案旨在帮助应届毕业生在求职过程中更好地准备面试,提升面试成功率。 资源内容 面试题目:涵盖了各大公司在模数电领域的常见面试问题。 答案解析:每个问题都附有详...

gitblog_06672的博客 413

PHP基础笔试题目:我的视角与思考

它不仅要求我们掌握基本的语法和函数,还要求我们具备良好的编程思维和解决问题的能力。只有通过不断地学习和实践,我们才能更好地掌握PHP编程的精髓,并在未来的职业生涯中取得更大的成就。在函数内部定义的变量,如果没有使用特定的关键字进行声明,那么它只能在函数内部被访问,这就是所谓的局部变量。在编写代码的过程中,我时常会回想起那些曾经让我头疼的函数和类,但正是这些挑战和困难,让我不断地成长和进步。PHP,这个曾经陪伴我走过无数日夜、敲下无数代码的编程语言,它的每一个细节、每一个函数,都深深地印在我的脑海中。

2401_85969294的博客 309

谈谈思考

《好好说话》是喜马拉雅APP一档教人如何说话的节目,片头有这么一句话:“脑子想的通,说话才能说通;说话说得通,做事才能做通”。看似是一档说话的节目,实际上更多的是教你思考。通过思考,把事情想明白了,说话、做事自然也就对了。很长的一段时间,我其实是不知道如何正确思考的,傻傻的以为把问题丢到大脑中,随着时间推进,答案就会慢慢的自己跳出来。隐隐的觉得哪里不对,但又说不出所以然。《好好说话》有一期节目叫“

田攀的日志 1761
上一篇: LeetCode 72.编辑距离
下一篇: 算法设计课作业
ByteMaster_
博客等级 码龄3年 328粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值