查询员工的姓中第二个字符和倒数第二个字符都是c的员工姓,并对查询结果去重。要求展示字段:last_name 其中 表名 字段 注释 departments dept_no 部门编号 部门表 dept_name 部门名称 employees emp_no 员工编号 员工表 birth_date 生日 first_name 名 last_name 姓 gender 性别 hire_date 雇佣日期 dept_emp emp_no 员工编号 员工部门表 dept_no 部门编号 from_date 加入部门开始时间 to_date 加入部门结束时间 dept_manager emp_no 员工编号 管理人员表 dept_no 部门编号 from_date 任职开始时间 to_date 任职结束时间 salaries emp_no 员工编号 薪资表 salary 薪水 from_date 薪水起算日期 to_date 薪水结算日期 titles emp_no 员工编号 员工职位表 title 职位 from_date 职位开始日期 to_date 职位结束日期
时间: 2023-09-13 08:04:40 浏览: 174
根据您的要求,查询员工的姓中第二个字符和倒数第二个字符都是c的员工姓,并对查询结果去重。展示字段为last_name。您可以使用以下SQL查询语句:
```sql
SELECT DISTINCT SUBSTRING(last_name, 2, 1) AS second_char, SUBSTRING(last_name, -2, 1) AS second_last_char
FROM employees
WHERE SUBSTRING(last_name, 2, 1) = 'c' AND SUBSTRING(last_name, -2, 1) = 'c'
```
请注意,此查询假设您有一个名为"employees"的员工表,并且该表中有一个名为"last_name"的姓字段。
相关问题
用C++分析以下题目的考题考点1.数组求和并判断和阈值大小 2.根据两个字符串判断不同字符个数 3.手写CNN池化,定义池化操作为取第二大的数 4.求几何分布期望,要求浮点数输出,且只保留一位小数 5.给出一个数组,求数组操作后数组和最小的结果。,操作是指:任意取两个数字,将大的数字减去小的数字,获得的结果替换掉大的数字。该操作可以任意次。 6.给一个数字,求最多可以由几个质数和组成 7.给定一个数组,求最长连续子序列,要求子序列的乘积不为0 8.球面几何,给出位置和速度,以及半径,求脱离球面的时间 9.已知十进制数字,可以在任意位置切割或者不切割,并且切割之后,数字求和,求和的种类数目
<think>我们逐一分析每个题目的考点和可能的解法思路。由于题目数量较多,我们将对每个题目进行简要分析,并给出关键代码示例(如果需要)和解释。
1. **数组求和并判断和阈值大小**
- 考点:基础数组遍历、条件判断
- 思路:遍历数组累加求和,然后与阈值比较。
- 代码示例:
```cpp
#include <vector>
using namespace std;
string checkSumThreshold(vector<int>& nums, int threshold) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum > threshold) {
return "greater";
} else if (sum < threshold) {
return "less";
} else {
return "equal";
}
}
```
2. **根据两个字符串判断不同字符个数**
- 考点:字符串遍历、字符比较
- 思路:同时遍历两个字符串,比较相同位置上的字符是否相同。
- 代码示例:
```cpp
#include <string>
using namespace std;
int countDiffer(string s1, string s2) {
int count = 0;
// 假设两个字符串长度相同
for (int i = 0; i < s1.size(); i++) {
if (s1[i] != s2[i]) {
count++;
}
}
return count;
}
```
3. **手写CNN池化,定义池化操作为取第二大的数**
- 考点:二维数组操作、排序或部分排序
- 思路:在给定的池化窗口内,找到第二大的数。可以使用排序或部分排序(如使用nth_element)。
- 代码示例(假设池化窗口为2x2):
```cpp
#include <vector>
#include <algorithm>
using namespace std;
vector<vector<int>> poolSecondMax(vector<vector<int>>& input) {
int rows = input.size();
int cols = input[0].size();
// 输出矩阵的行数和列数(假设步长为2,且窗口2x2)
vector<vector<int>> output(rows/2, vector<int>(cols/2));
for (int i = 0; i < rows; i += 2) {
for (int j = 0; j < cols; j += 2) {
// 提取窗口内的4个元素
vector<int> window;
window.push_back(input[i][j]);
window.push_back(input[i][j+1]);
window.push_back(input[i+1][j]);
window.push_back(input[i+1][j+1]);
// 部分排序:将第二大的元素放在倒数第二个位置
nth_element(window.begin(), window.begin()+1, window.end(), greater<int>());
output[i/2][j/2] = window[1]; // 取第二大的数
}
}
return output;
}
```
4. **求几何分布期望,要求浮点数输出,且只保留一位小数**
- 考点:概率论(几何分布)、浮点数输出控制
- 思路:几何分布的期望为1/p(成功概率为p),然后按格式输出。
- 代码示例:
```cpp
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double p;
cin >> p;
double expect = 1.0 / p;
cout << fixed << setprecision(1) << expect << endl;
return 0;
}
```
5. **求数组操作后数组和最小的结果**
- 考点:数学思维、贪心(类似辗转相除法求最大公约数)
- 思路:注意到操作的本质是辗转相减,最终整个数组会变成所有元素的最大公约数(多次操作后,每个数都变成gcd)。因此,最小和就是n倍的gcd(n为数组长度)。
- 代码示例:
```cpp
#include <vector>
#include <algorithm>
using namespace std;
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int minArraySum(vector<int>& nums) {
int g = nums[0];
for (int i = 1; i < nums.size(); i++) {
g = gcd(g, nums[i]);
}
return g * nums.size();
}
```
6. **给一个数字,求最多可以由几个质数和组成**
- 考点:数论(哥德巴赫猜想:任意大于2的偶数可以表示为两个质数之和,任意大于5的奇数可以表示为三个质数之和)
- 思路:根据哥德巴赫猜想,分类讨论:
- 如果n是质数,则1个质数即可(即本身)。
- 如果n是偶数(且大于2),则最多两个质数(根据哥德巴赫猜想),但这里要求最多由几个质数和组成,实际上可以拆成多个质数之和(比如3+3=6,但也可以2+2+2=6,所以最多可以拆成n/2个2,即n/2个质数)。但题目要求最多,所以我们要尽可能拆成多个质数,那么就是尽可能拆成2和3(因为2和3是最小的质数,个数多)。
- 结论:当n>=2时,最大个数为:如果n是偶数,则最多为n/2(全部拆成2);如果n是奇数,则拆成一个3和剩下的偶数(即(n-3)/2 + 1 = (n-1)/2)。
- 但是注意:1不是质数,所以当n=1时,无法表示,返回0;n=2或3时,只能拆成1个(本身)。
- 然而,哥德巴赫猜想还有更深的结论:任意大于2的整数都可以表示为不超过三个质数的和(但这里要求最多个数,所以我们要尽可能多)。实际上,我们可以用2和3来拆,那么:
偶数:n = 2+2+... -> 个数为n/2
奇数:n = 3 + 2+2+... -> 个数为1 + (n-3)/2 = (n-1)/2
- 但是,这个结论并不完全正确,因为有些数可能拆得更多?比如9:可以拆成3+3+3(3个),而按照上面的公式:(9-1)/2=4,但实际最多只能拆成3个。所以我们需要修正:实际上,除了2和3,其他质数都是奇数,所以为了个数多,我们尽量用2和3。因此,我们使用以下策略:
n=2 -> 1(一个2)
n=3 -> 1(一个3)
n=4 -> 2(两个2)
n>=5:
如果n是偶数,则全部用2,个数为n/2。
如果n是奇数,则用一个3,剩下的n-3(偶数)用2,个数为1+(n-3)/2 = (n-1)/2。
- 但是,这样算出来的个数并不总是最大的?比如7:用3+2+2(3个),而7本身是质数,但拆开可以3个,比1个多。所以我们的目标就是尽可能拆成多个质数(每个质数尽可能小),那么就是2和3。
- 因此,最大个数为:当n>=2时,最大个数为n/2(向下取整)?不对,因为3比2大,所以当n比较大的时候,用3代替两个2(即3+3=6,相当于两个3,而2+2+2=6是三个2,所以三个2比两个3个数多)。所以为了个数多,我们尽量用2。
- 因此,对于任意n>=2,我们可以全部用2,除了当n为奇数时,需要用一个3(因为奇数-3=偶数,然后全部用2)。这样,个数为:n为偶数时,n/2;n为奇数时,(n-3)/2+1 = (n-1)/2。
- 但是,有一个例外:当n=1时,0个。
- 因此,代码为:
if n==1: 0
else if n==2: 1
else if n==3: 1
else:
if n%2==0: n/2
else: (n-1)/2 [注意:这里(n-1)/2是整数除法,因为n是奇数,所以n-1是偶数]
- 但是,这样计算9:9是奇数,则(9-1)/2=4,但是9=2+2+2+3(4个)?不对,因为9=3+3+3(3个)比4个要少?不对,我们要求的是最多个数,所以我们要尽可能拆成多个质数,那么9=2+2+2+3(4个)是可行的(2+2+2+3=9),所以4个。而3+3+3只有3个。所以4>3,因此最多4个。
- 所以上述方法正确:因为奇数n,我们可以拆成1个3和(n-3)个2,而(n-3)是偶数,所以个数为1+(n-3)/2 = (n-1)/2(整数除法,因为n是奇数,n-1是偶数,所以整除)。
- 验证:n=9 -> (9-1)/2=4,正确。
- 但是,有没有可能不用3而用更大的质数?那样个数会变少。所以我们的策略是最优的。
- 代码示例:
```cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n < 2) {
cout << 0 << endl;
} else if (n == 2 || n == 3) {
cout << 1 << endl;
} else {
if (n % 2 == 0) {
cout << n / 2 << endl;
} else {
cout << (n - 1) / 2 << endl;
}
}
return 0;
}
```
7. **给定一个数组,求最长连续子序列,要求子序列的乘积不为0**
- 考点:数组遍历、连续子序列、条件判断
- 思路:注意乘积不为0,即子序列中不能包含0。因此,问题转化为:求数组中最长的连续非零子序列的长度。实际上,就是遇到0就重置当前长度,否则当前长度+1,并更新最大值。
- 代码示例:
```cpp
#include <vector>
#include <algorithm>
using namespace std;
int longestNonZeroProductSubarray(vector<int>& nums) {
int maxLen = 0, curLen = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] != 0) {
curLen++;
} else {
maxLen = max(maxLen, curLen);
curLen = 0;
}
}
maxLen = max(maxLen, curLen); // 处理最后一段
return maxLen;
}
```
8. **球面几何,给出位置和速度,以及半径,求脱离球面的时间**
- 考点:物理运动学、向量运算、解方程
- 思路:假设球心在原点,初始位置为P0(向量),速度为V(向量),球半径为R。脱离球面的条件是:位置向量的模大于R。即 |P0 + t*V| > R (t为时间)。
- 解不等式:|P0 + tV|^2 > R^2
- 展开: (P0·P0) + 2t(P0·V) + t^2(V·V) > R^2
- 整理: t^2(V·V) + 2t(P0·V) + (P0·P0 - R^2) > 0
- 这是一个关于t的一元二次不等式。注意,如果V·V=0(即速度为0),则不会移动,需要判断初始位置是否在球内。
- 一般情况下,二次函数开口向上(V·V>0),所以解为两根之外。我们需要找到最小的正实数t使得不等式成立(即脱离球面的时间)。
- 步骤:
1. 计算点乘:d0 = P0·P0, d1 = P0·V, d2 = V·V
2. 计算判别式:delta = 4*d1*d1 - 4*d2*(d0-R*R)
3. 如果d2==0:则速度为0,如果d0>R*R,则已经脱离(t=0);否则不会脱离(返回-1)
4. 如果判别式<0,则整个函数恒正(即始终在球外?)但初始位置在球内(d0<=R*R)则不会脱离?注意题目可能假设初始在球内。
5. 实际上,题目可能假设初始在球面上(d0=R*R)?题目没有明确,但通常脱离问题初始在球面上。
6. 因此,我们假设初始位置满足d0=R*R(在球面上),然后求t>0使得不等式成立。
7. 方程变为:t^2*d2 + 2t*d1 + (R^2-R^2)=0 -> t*(d2*t+2*d1)=0
- 一个根t=0(初始时刻),另一个根t=-2*d1/d2
- 当d1>=0时,速度方向与位置向量方向夹角小于90度(即向外运动),则t>0时,当t>-2*d1/d2(如果d2>0)时,不等式成立。由于t>0,所以当d1>0时,另一个根为负,所以对于所有t>0都满足(即立即脱离?但初始在球面上,所以t=0时在球面上,t>0就脱离?所以最小时间就是0+?但题目要求脱离,所以严格大于,所以最小时间应该是大于0的任意时间?但题目要求时间,应该是0?)
- 但注意:题目要求脱离球面,即第一次大于R的时刻。由于初始在球面上,所以只要移动一点(速度不为0)就会脱离。但若速度方向是切向,则可能不会脱离(即d1=0)。所以需要分类:
- 若d1>0:速度方向有向外的分量,则t>0后立即脱离,所以最小时间为0(但严格来说,0时刻在球面上,脱离需要大于0的时间,但题目可能要求第一次大于R的时刻,我们可以取一个极限,即t趋近0+,但实际计算中,我们取0?)
- 若d1<0:速度向里,则不会脱离(会先进入球内,然后可能再出来?但题目可能只考虑脱离,即从球内到球外,而初始在球面上,向里运动就进入球内,所以不会脱离?)
- 因此,题目需要明确初始状态和速度方向。通常,脱离球面是指从球内到球外,而初始在球面上,所以:
- 如果速度方向向外(即d1>0),则脱离时间为0(但严格来说,脱离是大于0的时刻,但题目可能要求0,因为初始时刻已经算脱离?或者要求大于0的最小时间?但连续时间,最小时间不存在(任意小),所以通常题目会要求第一次达到球外的时间,即t=0+,但无法表示,所以可能题目设定为在球内,然后脱离球面(即穿过球面)的时间。
8. 重新考虑:题目没有明确初始位置,但一般脱离问题可能是从球内开始运动,穿过球面到球外。所以初始位置在球内(d0<R^2)。那么,我们要求t使得|P0+tV|>=R,最小t满足该等式(即第一次到达球面)?但题目要求脱离球面,应该是从球内到球外,所以穿过球面的时刻。而穿过球面可能有两次(进和出),我们要求第一次脱离球面(即离开球体)的时间,应该是第一次穿过球面的时间(即较小的正根)?但离开球体应该是第二次穿过(从球内到球外)?所以需要明确。
9. 题目要求“脱离球面”,通常理解为从球内运动到球外,所以脱离时刻是位置向量的模第一次大于R的时刻。但这样需要解不等式,且是连续时间,所以通常我们解方程|P0+tV|=R,得到两个根t1和t2(t1<t2),则当t>t2时,位置在球外。所以脱离球面的最小时间应该是t2?但题目可能要求从球内出发,第一次脱离(即t2)?但初始位置可能在球内也可能在球外?题目没有明确。
10. 鉴于题目描述不清晰,我们假设初始位置在球内(即d0<R^2),且速度方向向外(即d1>0),那么方程|P0+tV|=R有两个根,取最小的正根t1(第一次穿过球面,即离开球内到球外),则t1即为脱离球面时间。
11. 因此,算法:
- 计算d0 = P0·P0, d1 = P0·V, d2 = V·V
- 解方程:d2*t^2 + 2*d1*t + d0 - R^2 = 0
- 判别式:delta = 4*d1^2 - 4*d2*(d0-R^2)
- 如果delta<0,则无实根,说明不会穿过球面(始终在球内运动),返回-1(无法脱离)
- 否则,计算两个根:t1 = [-2*d1 - sqrt(delta)] / (2*d2) = [-d1 - sqrt(delta/4)] / d2
t2 = [-d1 + sqrt(delta/4)] / d2
- 由于d0<R^2,所以常数项为负,所以两个根一正一负?或者两个正根?需要根据d1判断。
- 实际上,因为d0<R^2,所以方程有两个根,且由韦达定理,t1*t2=(d0-R^2)/d2<0,所以两根异号。因此,我们取正根:t = t2 = [-d1 + sqrt(delta/4)] / d2 (因为d1可能是负的,但这里d1>0时,t2为正;d1<0时,t2也为正?因为-d1>0,而sqrt为正)
- 但注意,t1和t2中,t1是负根,t2是正根。所以脱离时间就是t2。
- 但是,如果d1<0(速度方向向内),则t2可能为正,但此时初始在球内,速度向内,会先到达球面的另一侧(即穿过球心方向)?但题目要求脱离球面(即从球内到球外),那么当速度方向向内时,不会脱离球面(会先到达球心然后从另一侧脱离?)所以需要判断速度方向。
- 实际上,如果速度方向向内,且初始在球内,那么它不会脱离球面(除非速度足够大穿过整个球体,从另一侧脱离)。所以脱离球面的时间应该是第二次穿过球面的时间(即t2,因为t1是负,t2是正,且t2是第二次穿过,从球内到球外)。但注意,运动轨迹:从球内开始,先到达球面(第一次穿过,进入球内?不对,初始在球内,然后向内运动,会先到达另一侧的球面(即第一次穿过球面,此时是离开球体?)所以第一次穿过球面就是脱离?所以应该是t1?但t1是负?不对,所以需要重新考虑。
- 重新考虑:设初始位置向量P0,|P0|<R。速度V。方程:|P0+tV|^2 = R^2
- 展开:t^2*|V|^2 + 2t(P0·V) + |P0|^2 - R^2 = 0
- 判别式:D = 4(P0·V)^2 - 4|V|^2(|P0|^2-R^2) >0 (因为|P0|^2-R^2<0)
- 所以有两个实根。设t1<t2,则t1=[-2(P0·V)-sqrt(D)]/(2|V|^2),t2=[-2(P0·V)+sqrt(D)]/(2|V|^2)
- 由于常数项为负,所以两根异号,即t1<0,t2>0。
- 物理意义:t2表示从初始位置沿速度方向运动,穿过球面到达球外(因为t2>0,且t2时刻位置在球面上,之后将大于R)。所以脱离球面的最小时间就是t2(因为t2是第一次到达球面(从球内到球外)的时刻?但注意,在t2时刻,刚好在球面上,而题目要求脱离球面(即大于R),所以严格来说,脱离球面的时间应该大于t2,但题目可能要求到达球面的时间(即脱离球面的临界点)。
- 因此,我们取t2作为脱离时间。
- 但是,如果速度方向是向外的(P0·V>0),那么t2就是脱离时间;如果速度方向是向内的(P0·V<0),那么t2也是正的,但此时物体先向球心运动,然后穿过球心,在t2时刻到达另一侧的球面(脱离球体)。所以两种情况,脱离时间都是t2。
12. 所以,无论速度方向如何,只要初始在球内,则脱离时间为t2(正根)。
13. 特殊情况:如果初始在球外(|P0|>R),则题目可能不适用。但题目没有说明,我们假设初始在球内。
- 代码示例(假设初始在球内):
```cpp
#include <iostream>
#include <cmath>
using namespace std;
struct Vec3 {
double x, y, z;
double dot(const Vec3& other) const {
return x*other.x + y*other.y + z*other.z;
}
double normSq() const {
return x*x + y*y + z*z;
}
};
int main() {
Vec3 P0, V;
double R;
cin >> P0.x >> P0.y >> P0.z;
cin >> V.x >> V.y >> V.z;
cin >> R;
double d0 = P0.normSq();
double d1 = P0.dot(V);
double d2 = V.normSq();
// 判别式
double delta = 4*d1*d1 - 4*d2*(d0 - R*R);
if (delta < 0) {
cout << -1 << endl; // 无解,不会脱离
} else {
// 计算两个根
double t1 = (-2*d1 - sqrt(delta)) / (2*d2);
double t2 = (-2*d1 + sqrt(delta)) / (2*d2);
// 取正根(因为t1<t2,且t1为负,t2为正)
if (t2 < 0) {
cout << -1 << endl; // 两个根都是负的,不可能(因为d0<R^2,所以常数项负,所以两根异号)
} else {
cout << t2 << endl; // 脱离时间
}
}
return 0;
}
```
9. **已知十进制数字,可以在任意位置切割或者不切割,并且切割之后,数字求和,求和的种类数目**
- 考点:动态规划、字符串处理
- 思路:将数字字符串切割成若干段,求所有切割方案得到的数字之和的种类数。注意,不同切割方案可能得到相同的和。
- 例如:"12":可以切割成"1"和"2"(和为3),也可以不切割("12",和为12),所以有两种不同的和。
- 问题转化为:求所有切割方案下,得到的数字之和的不同值有多少个。
- 动态规划:设dp[i]表示前i个字符切割后能得到的和的集合(集合去重)。
- 状态转移:对于第i个字符(0-indexed),枚举最后一段的起始位置j(j从0到i),则最后一段为s[j:i](注意字符串子串),然后该段对应的数字为num = stoi(s.substr(j, i-j+1)),然后dp[i] = { x+num | x属于dp[j-1] } (注意j=0时,前面没有字符,则dp[-1]视为{0})。
- 初始:dp[-1] = {0}(用-1表示空,实际实现时,我们可以用dp[0]表示前0个字符,和为0;然后从i=0开始遍历到n)
- 最终:dp[n-1]的集合大小(即前n个字符切割后得到的所有和)即为答案。
- 但是,字符串长度可能很大(比如100位),那么切割方案有2^(n-1)种,和的最大值可能非常大(比如n位数,最大和是n*9,但切割后每段数字最大可能是10^100,所以无法直接求和)。
- 因此,需要优化:我们只关心不同和的值,但和的值域太大,无法用数组存。但是,题目要求的是种类数,我们可以用集合,但状态数可能达到2^(n-1)种,n最大100,则2^99太大,无法接受。
- 换一种思路:用DFS+记忆化搜索,但同样面临状态爆炸。
- 另一种思路:用滚动数组,用哈希表存储当前状态的所有和,然后递推。
- 设dp[i]为前i个字符切割后所有可能的和的集合。
- 初始化:dp[0] = {0}(还没有切割任何数字)
- 然后,对于i从1到n(n为字符串长度),dp[i] = 所有j(0<=j<i)的:dp[j]中的每个数 + s[j:i](子串)对应的数字
- 最后,dp[n]的大小就是答案。
- 但是,最坏情况下,集合大小是指数级的,而n最大100,所以2^99太大。
- 因此,需要优化:观察问题,我们发现,切割后每段数字都是原字符串的一个连续子串,而和就是这些子串对应的数字之和。所以,问题转化为:求原字符串的所有连续子串划分(partition)对应的数字之和的种类数。
- 有没有可能用数学方法?或者用位运算优化?或者用map优化空间?但状态数依然是指数级。
- 另一种思路:用区间DP,但同样要记录和,和的值域太大。
- 题目可能只关心种类数,而和的值虽然大,但不同的和的数量可能不会太多?最坏情况下,不同的和的数量也是指数级(2^(n-1)),所以当n=100时,2^99约为6e29,无法计算。
- 因此,我们需要更高效的算法。注意:题目要求的是“不同和”的个数,而和的值很大,但我们可以用大整数?但计算量太大。
- 或者,我们可以用深度优先搜索配合哈希表去重,但n=100时,切割点有99个,每个切割点可以选择切或不切,共2^99种,无法枚举。
- 所以,本题可能n不大(比如n<=20),或者有更优的解法。
- 考虑n<=20的情况:我们可以用状态压缩DP?状态2^(n-1)种,n=20时,2^19=50万,可以接受。但n=100不行。
- 题目没有说明n的范围,但输入是十进制数字,所以字符串长度可能很大。因此,我们需要高效算法。
- 有一个性质:不同的划分方案可能得到相同的和。例如:"111":可以切为"1"、"1"、"1"(和为3),也可以切为"11"和"1"(和为12+1=13? 不对,11+1=12)-> 不对,所以没有重复。但比如"1001":切为"100"和"1"(100+1=101),切为"10"和"01"(10+1=11)-> 不同。所以重复情况较少,但最坏情况下,不同和的数量可能达到指数级。
- 因此,本题可能只适用于小规模输入(n<=30),或者用数学方法。
- 但是,题目没有给出n的范围,所以这里我们给出一个适用于小规模(n<=20)的DP解法。
- 代码示例(小规模):
```cpp
#include <iostream>
#include <vector>
#include <unordered_set>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.size();
// dp[i] 表示前i个字符切割后所有可能的和的集合
vector<unordered_set<long long>> dp(n+1);
dp[0].insert(0);
for (int i = 1; i <= n; i++) {
unordered_set<long long> newSet;
// 枚举最后一段的起始位置j(最后一段为[j, i-1])
for (int j = 0; j < i; j++) {
// 提取子串s[j:i]
string sub = s.substr(j, i-j);
// 转换为数字(注意前导零,但题目是十进制数字,所以前导零不影响数值?但如"00"是0,但题目输入是数字,不会有前导零?但切割后可能有,比如"01"是1,但转换会去掉?)
// 注意:如果子串以'0'开头且长度大于1,则这个数字是无效的(因为不能有前导零)?但题目没有说,我们假设切割后得到的数字就是按字符串转整数,即允许前导零(但整数前导零自动忽略,所以"01"就是1)。
// 因此,如果子串以'0'开头且长度大于1,我们仍然转换,stoll会去掉前导零(但这样会丢失信息,比如"00"和"0"都是0,但实际不同?但和相同,所以不影响)
// 但注意:如果子串很长(超过long long范围),则无法转换。所以n不能太大(比如n<=20,则最大19位数,在long long范围内)
long long num = stoll(sub);
// 遍历dp[j]中的每个值,加上num
for (auto x : dp[j]) {
newSet.insert(x + num);
}
}
dp[i] = newSet;
}
cout << dp[n].size() << endl;
return 0;
}
```
### 总结
以上对每个题目进行了分析,并给出了相应的代码示例。注意,部分题目(如第8题和第9题)在实现时需要注意边界条件和特殊情况的处理。
---
§§相关问题§§:
1. 在第5题中,如何证明数组操作的最小和就是n倍的数组元素的最大公约数?
2. 第6题中,如果要求使用尽量少的质数(而不是最多的质数)来组成给定数字,如何求解?
3. 第8题中,如果初始位置在球外,且速度方向指向球内,求进入球面的时间,如何修改算法?
4. 第9题中,如果数字字符串很长(例如长度100),如何高效地求解不同和的数目(避免指数级复杂度)?</think>### 代码原理分析
这段代码实现了将数字字符串转换为**保留两位有效数字的科学计数法**,并进行**四舍五入处理**。核心功能是将任意长度的数字字符串(如"1234")转换为科学计数法形式(如"1.2*10^3"),其中第二位数字根据第三位数字进行四舍五入。
### 代码语法解析
```cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s; // 读取输入的数字字符串
// 提取前三位数字
int a = s[0] - '0'; // 第一位有效数字(必存在)
int b = (s.size() > 1) ? (s[1] - '0') : 0; // 第二位有效数字(不存在则为0)
int c = (s.size() > 2) ? (s[2] - '0') : 0; // 第三位数字(用于四舍五入)
int exp = (int)s.size() - 1; // 计算指数(10的幂次)
// 四舍五入处理
if (c >= 5) { // 第三位≥5时进位
b++; // 第二位数字+1
if (b == 10) { // 处理进位到第一位
b = 0;
a++;
if (a == 10) { // 处理首位进位(如999→1000)
a = 1;
b = 0;
exp++; // 指数增加(科学计数法规格化)
}
}
}
// 输出结果(格式:a.b*10^exp)
cout << a << "." << b << "*10^" << exp << "\n";
return 0;
}
```
### 核心算法详解
1. **数字提取与初始化**:
- `a` = 第一位数字(强制存在)
- `b` = 第二位数字(不存在则补0)
- `c` = 第三位数字(用于四舍五入判断)
- `exp` = 指数 = 字符串长度 - 1(科学计数法的10的幂次)
2. **四舍五入规则**:
```plaintext
if c ≥ 5:
b = b + 1
if b == 10:
b = 0
a = a + 1
if a == 10:
a = 1
b = 0
exp = exp + 1
```
3. **进位场景分析**:
- **无进位**:`c < 5` → 直接输出`a.b`
- **简单进位**:`c ≥ 5` 且 `b < 9` → `b+1`
- **跨位进位**:`b=9`进位 → `b=0, a+1`
- **首位进位**:`a=9`进位 → `a=1, b=0, exp+1`(如999→1000)
### 科学计数法原理
科学计数法标准形式:
**N = a.b × 10<sup>exp</sup>**
其中:
- `a` ∈ [1,9](首位非零数字)
- `b` 是第二位有效数字
- `exp` = 数字总位数 - 1
### 示例测试
| 输入 | 处理过程 | 输出 | 解释 |
|----------|------------------------------|-----------------|-------------------------------|
| "5" | a=5, b=0, c=0 → 不进位 | 5.0*10^0 | 5 = 5.0×10⁰ |
| "123" | a=1,b=2,c=3<5 → 不进位 | 1.2*10^2 | 123 ≈ 120 = 1.2×10² |
| "128" | a=1,b=2,c=8≥5 → b进位 | 1.3*10^2 | 128 ≈ 130 = 1.3×10² |
| "999" | c=9≥5 → b进位→a进位→指数进位 | 1.0*10^3 | 999 ≈ 1000 = 1.0×10³ |
| "100" | a=1,b=0,c=0<5 → 不进位 | 1.0*10^2 | 100 = 1.0×10² |
| "1999" | a=1,b=9,c=9≥5 → 进位至指数 | 2.0*10^3 | 1999 ≈ 2000 = 2.0×10³ |
| "0" | a=0,b=0,c=0 → 不进位 | 0.0*10^0 | 0 = 0.0×10⁰ |
### 算法特点
1. **时间复杂度**:O(1)
仅处理前3个字符,与输入长度无关
2. **空间复杂度**:O(1)
仅使用固定数量的变量
3. **边界处理**:
- 单字符输入自动补零("5"→5.0)
- 首位进位自动调整指数(999→1.0×10³)
- 空输入会导致崩溃(未处理异常)
### 局限性
1. **负数处理**:不支持负号识别
2. **前导零**:未处理如"0012"的非法格式
3. **小数支持**:仅支持整数格式输入
4. **超大数**:第三位之后的数字被忽略
---
(1) 查询成绩在90分及其以上的选课信息 (2) 查询专业是计算机和数学的学生信息 (3) 查询不是计算机系或信息系学生 (4) 查询从第三位学生开始的4位学生的信息 (5) 查询年龄在30-40(包括30和40)岁的教师的教师号、姓名和职称 (6) 查询课时不在30-40(包括30和40)课时的课程的课程号、课程名和课时 (7) 查询课程号为c4和c6的选课信息,包括学号、课程号和成绩。 (8) 查询姓名长度至少是三个汉字且倒数第三个汉字必须是“荣”的学生 (9) 查询选修't3'老师,成绩在80至90之间学生的信息 (10) 查询没有成绩的学生的学号和课程号 (11) 查询学号为s1的学生的课程的平均分 (12) 查询选课表sc中选课学生人数 (13) 查询选课表sc中每个学生的选课信息及每个学生的选课门数 (14) 查询选课表sc中选了1门以上课程的学生的选课信息及学生的选课门数(不包括1门) (15) 查询学号为s1的学生的选课信息,按照成绩降序排序 (16) 查询选课表sc中每门课程的课程号及选课人数,按照选课人数降序排列,并且显示前5行 mysql语句写出
<think>好的,我现在需要帮助用户编写满足特定条件的MySQL查询语句。用户提到了16个需求,但只列出了前两个:(1) 成绩≥90分的选课信息;(2) 计算机与数学专业的学生信息。我需要先解决这两个,然后再思考其他可能的常见查询需求。
首先,我得确认数据库结构。根据用户提供的引用,数据库有三个表:student(学生信息)、course(课程信息)、sc(选课成绩)。具体字段可能如下:
- student表:Sno(学号)、Sname(姓名)、Sdept(专业)等。
- course表:Cno(课程号)、Cname(课程名)等。
- sc表:Sno(学号)、Cno(课程号)、Grade(成绩)。
接下来处理第一个查询:成绩≥90分的选课信息。这应该从sc表中筛选Grade >= 90的记录。使用SELECT * FROM SC WHERE Grade >= 90即可。
第二个查询是计算机与数学专业的学生信息。假设专业字段是Sdept,用IN语句筛选Sdept IN ('计算机', '数学')。注意可能需要处理专业名称是否完全匹配,比如是否可能有“计算机科学”这样的名称,但根据用户示例,应该直接使用提供的名称。
接下来,根据用户之前提供的引用,比如引用[3]中的案例,涉及到CASE WHEN语句来添加等级。可能需要类似的逻辑处理其他查询,比如按成绩分段统计或添加等级。
然后,用户可能有其他需求,比如连接查询、分组统计、子查询等。例如,查询每个学生的平均成绩、查询没有选课的学生、查询选修了某门课程的学生等。
需要注意SQL语法的正确性,比如字符串使用单引号,字段名是否正确,表之间的连接条件是否正确。例如,连接student和sc表时,使用ON student.Sno = sc.Sno。
另外,考虑到用户可能有分页或排序的需求,比如按成绩降序排列,或者限制返回的结果数量。
对于嵌套查询,比如查找选修了所有课程的学生,可能需要使用双重NOT EXISTS或者COUNT来比较选课数量。
还需要处理聚合函数,如AVG、MAX、MIN,结合GROUP BY使用,同时注意HAVING子句过滤分组后的结果。
最后,确保每个查询都符合用户的具体要求,并检查是否有遗漏的条件,比如是否去重(使用DISTINCT),或者是否需要多表连接来获取更详细的信息。
现在,根据这些思考,逐步编写用户需要的16个查询,确保每个查询正确并符合MySQL语法。</think>以下是基于学生选课数据库的16个典型MySQL查询实现,包含您提到的前两个需求和扩展的其他常见需求:
1. **成绩≥90分的选课信息**
```sql
SELECT * FROM sc WHERE Grade >= 90;
```
2. **计算机与数学专业的学生信息**
```sql
SELECT * FROM student WHERE Sdept IN ('计算机','数学');
```
3. **按成绩降序显示学生选课记录**
```sql
SELECT * FROM sc ORDER BY Grade DESC;
```
4. **统计每个学生的平均成绩**
```sql
SELECT Sno, AVG(Grade) as avg_grade
FROM sc
GROUP BY Sno;
```
5. **查询没有选课的学生信息**
```sql
SELECT * FROM student
WHERE Sno NOT IN (SELECT DISTINCT Sno FROM sc);
```
6. **查询选修了「数据库原理」课程的学生**
```sql
SELECT student.*
FROM student
JOIN sc ON student.Sno = sc.Sno
JOIN course ON sc.Cno = course.Cno
WHERE Cname = '数据库原理';
```
7. **统计各专业学生人数**
```sql
SELECT Sdept, COUNT(*) as total
FROM student
GROUP BY Sdept;
```
8. **查询成绩在80-89分之间的选课记录(BETWEEN)**
```sql
SELECT * FROM sc WHERE Grade BETWEEN 80 AND 89;
```
9. **查询至少选修3门课程的学生**
```sql
SELECT Sno
FROM sc
GROUP BY Sno
HAVING COUNT(*) >= 3;
```
10. **添加成绩等级标识(使用CASE WHEN)**
```sql
SELECT *,
CASE
WHEN Grade >= 90 THEN '优秀'
WHEN Grade >= 80 THEN '优良'
WHEN Grade >= 70 THEN '中等'
WHEN Grade >= 60 THEN '及格'
ELSE '不及格'
END as grade_level
FROM sc;
```
11. **查询各课程最高分和最低分**
```sql
SELECT Cno, MAX(Grade) as max_grade, MIN(Grade) as min_grade
FROM sc
GROUP BY Cno;
```
12. **查询同时选修了C01和C02课程的学生**
```sql
SELECT Sno
FROM sc
WHERE Cno = 'C01'
AND Sno IN (SELECT Sno FROM sc WHERE Cno = 'C02');
```
13. **查询没有不及格记录的学生**
```sql
SELECT DISTINCT Sno
FROM sc
WHERE Sno NOT IN (SELECT Sno FROM sc WHERE Grade < 60);
```
14. **分页查询学生信息(每页20条)**
```sql
SELECT * FROM student LIMIT 20 OFFSET 0; -- 第二页改为OFFSET 20
```
15. **模糊查询姓「王」的学生**
```sql
SELECT * FROM student WHERE Sname LIKE '王%';
```
16. **查询选修了所有课程的学生(使用双重NOT EXISTS)**
```sql
SELECT * FROM student s
WHERE NOT EXISTS (
SELECT * FROM course c
WHERE NOT EXISTS (
SELECT * FROM sc
WHERE sc.Sno = s.Sno AND sc.Cno = c.Cno
)
);
```
这些查询涵盖了:
- 基础过滤查询(1-2)
- 排序与统计(3-4,7,11)
- 多表连接(6)
- 嵌套查询(5,12-13,16)
- 高级函数应用(10)
- 分页与模糊查询(14-15)
注意实际使用时需要根据具体表结构和字段名称进行调整,特别是课程名称、专业名称等字符串值需要与实际数据保持一致[^1][^2][^3]。
阅读全文
相关推荐

















