HJ41 称砝码
描述
现有n种砝码,重量互不相等,分别为 m1,m2,m3…mn ;
每种砝码对应的数量为 x1,x2,x3...xn 。现在要用这些砝码去称物体的重量(放在同一侧),问能称出多少种不同的重量。
注:
称重重量包括 0
数据范围:每组输入数据满足 1≤n≤10 , 1≤mi≤2000 , 1≤xi≤10
输入描述:
对于每组测试数据:
第一行:n --- 砝码的种数(范围[1,10])
第二行:m1 m2 m3 ... mn --- 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 .... xn --- 每种砝码对应的数量(范围[1,10])
输出描述:
利用给定的砝码可以称出的不同的重量数
方法一:集合
#include<iostream>
#include<vector>
#include<unordered_set>
#include<algorithm>
using namespace std;
int main(){
int n;
while(cin >> n){
vector<int> weight(n);
vector<int> num(n);
for(int i = 0; i < n; i++) //输入n种砝码重量
cin >> weight[i];
for(int i = 0; i < n; i++) //输入n种砝码的数量
cin >> num[i];
unordered_set<int> s; //集合用于去重
s.insert(0); //0也是一种
for(int i = 0; i < n; i++){ //对于每一种砝码
for(int j = 1; j <= num[i]; j++){ //用完之前数量之前
unordered_set<int> temp(s);
for(auto iter = temp.begin(); iter != temp.end(); iter++) //当前集合每个都可以加一次
s.insert(*iter + weight[i]);
}
}
cout << s.size() << endl; //最后集合的大小就是种类
}
return 0;
}
方法二:动态规划
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int n;
while(cin >> n){
vector<int> weight(n);
vector<int> num(n);
int sum = 0;
for(int i = 0; i < n; i++) //输入n种砝码重量
cin >> weight[i];
for(int i = 0; i < n; i++){//输入n种砝码的数量
cin >> num[i];
sum += num[i] * weight[i]; //砝码总重量
}
vector<bool> dp(sum + 1, false); //记录0到sum是否可行
dp[0] = true;
for(int i = 0; i < n; i++){ //遍历每一种砝码
for(int j = 0; j < num[i]; j++){ //遍历砝码每一个数量
for(int k = sum; k >= weight[i]; k--) //每次剩余的每个都可以添加
if(dp[k - weight[i]])
dp[k] = 1;
}
}
int count = 0;
for(int i = 0; i <= sum; i++) //找到为1的就是可以组成的质量,计数
if(dp[i])
count++;
cout << count << endl;
}
return 0;
}
HJ42 学英语
描述
Jessi初学英语,为了快速读出一串数字,编写程序将数字转换成英文:
具体规则如下:
1.在英语读法中三位数字看成一整体,后面再加一个计数单位。从最右边往左数,三位一单位,例如12,345 等
2.每三位数后记得带上计数单位 分别是thousand, million, billion.
3.公式:百万以下千以上的数 X thousand X, 10亿以下百万以上的数:X million X thousand X, 10 亿以上的数:X billion X million X thousand X. 每个X分别代表三位数或两位数或一位数。
4.在英式英语中百位数和十位数之间要加and,美式英语中则会省略,我们这个题目采用加上and,百分位为零的话,这道题目我们省略and
下面再看几个数字例句:
22: twenty two
100: one hundred
145: one hundred and forty five
1,234: one thousand two hundred and thirty four
8,088: eight thousand (and) eighty eight (注:这个and可加可不加,这个题目我们选择不加)
486,669: four hundred and eighty six thousand six hundred and sixty nine
1,652,510: one million six hundred and fifty two thousand five hundred and ten
说明:
数字为正整数,不考虑小数,转化结果为英文小写;
保证输入的数据合法
关键字提示:and,billion,million,thousand,hundred。
数据范围:1≤n≤2000000
输入描述:
输入一个long型整数
输出描述:
输出相应的英文写法
方法一:
#include <iostream>
#include <string>
using namespace std;
const string ones[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
const string tens[] = { "ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen" };
const string twenties[] = { "zero","ten","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety" };
const int ihundreds[] = { (int)1e2, (int)1e3, (int)1e6, (int)1e9, (int)1e12 };
const string hundreds[] = { "hundred", "thousand", "million", "billion" };
string itoe(long long n){
if (0<=n && n<=9){//个位数,直接输出
return ones[n];
}
if (10<=n && n<20){//十位数,直接输出
return tens[n%10];
}
if (20<=n && n<1e2){//20-100
return twenties[n/10] + (n%10 ? " " + ones[n%10] : "");
}
for (int i=0; i < 4; i++){//大于100
if (n < ihundreds[i+1]) {//确定范围
return itoe(n/ihundreds[i]) + " " + hundreds[i] + (n%ihundreds[i] ? (i ? " ": " and ") + itoe(n%ihundreds[i]) : "");//递归转换
}
}
return "";
}
int main(){
long long n;
while (cin>>n){
cout<<itoe(n)<<endl;
}
return 0;
}
方法二:模拟
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const vector<string> num1 = {"", "thousand", "million", "billion"};
const vector<string> num2 = {"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
const vector<string> num3 = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
const vector<string> num4 = {"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
int main(){
long n;
while(cin >> n){
vector<string> res;
string s = to_string(n);
vector<string> v;
int i = s.size() - 1;//此时i指向数字的最低位
while(i >= 0){//从低位开始每三位划分
int j = i;
while(j > 0 && i - j < 2) j--;
v.push_back(s.substr(j, i - j + 1));
i = j - 1;
}
reverse(v.begin(), v.end());
for(int i = 0; i < v.size(); ++i){
if(v[i].size() == 3){//三位数字
if(v[i][0] - '0' != 0){//最高位不为0时,需要跟上百
res.push_back(num2[v[i][0] - '0']);
res.push_back("hundred");
if(v[i][1] - '0' != 0 || v[i][2] - '0' != 0){
res.push_back("and");//个位或十位不为零食,需要and
}
}
if(v[i][1] - '0' == 1){//处理10-19
res.push_back(num4[v[i][2] - '0']);
}else {//处理20-99
res.push_back(num3[v[i][1] - '0']);
res.push_back(num2[v[i][2] - '0']);
}
}else if(v[i].size() == 2){//两位数字
if(v[i][0] - '0' == 1){//10-19
res.push_back(num4[v[i][1] - '0']);
}
else {//20-99
res.push_back(num3[v[i][0] - '0']);
res.push_back(num2[v[i][1] - '0']);
}
}else{//只有一位数字,直接在num2中对应英文,0-9
res.push_back(num2[v[i][0] - '0']);
}
res.push_back(num1[v.size() - i - 1]);//确定每三位的单位
}
for(auto it : res){//输出最后结果
if(it != "")
cout << it << ' ';
}
cout << endl;
}
return 0;
}
HJ43 迷宫问题
描述
定义一个二维数组 N*M ,如 5 × 5 数组下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。
数据范围: 2≤n,m≤10 , 输入的内容只包含 0≤val≤1
输入描述:
输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。
输出描述:
左上角到右下角的最短路径,格式如样例所示。
方法一:dfs递归+回溯
#include<iostream>
#include<vector>
using namespace std;
vector<pair<int, int> > res;
void dfs(vector<vector<int>>& matrix, int n, int m, int i, int j, vector<pair<int, int>>& paths){
paths.push_back(make_pair(i, j)); //记入路径
matrix[i][j] = 1; //经过部分设置为1,表示后续不能经过
if(i == n - 1 && j == m - 1){ //到达终点
res = paths;
return;
}
//四个方向搜索
if(i + 1 < n && matrix[i + 1][j] == 0)
dfs(matrix, n, m, i + 1, j, paths);
if(j + 1 < m && matrix[i][j + 1] == 0)
dfs(matrix, n, m, i, j + 1, paths);
if(i - 1 >= 0 && matrix[i - 1][j] == 0)
dfs(matrix, n, m, i - 1, j, paths);
if(j - 1 >= 0 && matrix[i][j - 1] == 0)
dfs(matrix, n, m, i, j - 1, paths);
paths.pop_back(); //回溯
matrix[i][j] = 0;
}
int main(){
int n, m;
while(cin >> n >> m){
vector<vector<int> > matrix(n, vector<int>(m, 0));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++) //输入迷宫矩阵
cin >> matrix[i][j];
vector<pair<int, int> > paths; //记录临时路径
dfs(matrix, n, m, 0, 0, paths); //dfs遍历矩阵
for(int i = 0; i < res.size(); i++) //输出路径
cout << "(" << res[i].first << "," << res[i].second << ")" << endl;
}
return 0;
}
方法二:dfs非递归+逆向搜索
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
int main(){
int n, m;
int direct[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
while(cin >> n >> m){
vector<vector<int> > matrix(n + 1, vector<int>(m + 1, 0));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) //输入迷宫矩阵
cin >> matrix[i][j];
stack<pair<int, int> > s; //记录深度优先的栈
s.push(make_pair(1, 1)); //第一个结点入栈
matrix[1][1] = 1;
vector<pair<int, int> > res;
while(!s.empty()){
auto p = s.top();
s.pop();
for(int i = 0; i < 4; i++){ //四个方向
int x = p.first + direct[i][0];
int y = p.second + direct[i][1];
if(x > 0 && y > 0 && x <= n && y <= m && matrix[x][y] == 0){ //确保不越界再看是否为0
matrix[x][y] = p.first * 100 + p.second; //修改矩阵为前一个的坐标,百位为i,个位为j
if(x == n && y == m) //到达终点
break;
s.push(make_pair(x, y));
}
}
}
int i = n;
int j = m;
while(matrix[i][j] != 1){ //直到遇到起点
res.push_back(make_pair(i, j)); //从终点逆向添加
int temp = matrix[i][j];
i = temp / 100;
j = temp % 100;
}
res.push_back(make_pair(1, 1)); //添加起点
for(int i = res.size() - 1; i >= 0; i--) //反向输出路径
cout << "(" << res[i].first - 1<< "," << res[i].second - 1<< ")" << endl;
}
return 0;
}
方法三:BFS
#include <bits/stdc++.h>
using namespace std;
int a[15][15],vis[15][15];
int b[4][2]={{-1,0},{0,1},{1,0},{0,-1}};//上下左右四个方向
pair<int,int> fa[15][15];//记录当前下标的父亲下标
void dfs(int x,int y){//dfs打印路径
if(x==0&&y==0)//如果到达左上角,则退出
return;
auto t=fa[x][y];
dfs(t.first,t.second);
printf("(%d,%d)\n",x,y);
}
int main(){
int n,m;
while(cin >> n >> m){
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin >> a[i][j];//输入迷宫
memset(vis,0,sizeof(vis));
memset(fa,0,sizeof(fa));
queue<pair<int,int>> q;//队列
q.push({0,0});//左上角坐标入队列
vis[0][0]=1;
while(!q.empty()){
auto u=q.front();
q.pop();
if(u.first==n-1&&u.second==m-1){
break;
}
for(int i=0;i<4;i++){//遍历四个方向
int nx=u.first+b[i][0],ny=u.second+b[i][1];
if(nx<0||nx>=n||ny<0||ny>=m)
continue;
if(vis[nx][ny]==0&&a[nx][ny]==0){//如果当前坐标未访问过并且可以走,则入队列,并且当前坐标指定父亲坐标
fa[nx][ny]={u.first,u.second};
q.push({nx,ny});
vis[nx][ny]=1;
}
}
}
printf("(%d,%d)\n",0,0);
dfs(n-1,m-1);
}
return 0;
}
HJ44 Sudoku
描述
问题描述:数独(Sudoku)是一款大众喜爱的数字逻辑游戏。玩家需要根据9X9盘面上的已知数字,推算出所有剩余空格的数字,并且满足每一行、每一列、每一个3X3粗线宫内的数字均含1-9,并且不重复。
例如:
输入
输出
数据范围:输入一个 9*9 的矩阵
输入描述:
包含已知数字的9X9盘面数组[空缺位以数字0表示]
输出描述:
完整的9X9盘面数组
方法一:递归
#include <iostream>
using namespace std;
int num[9][9];//用于保存9x9盘面
bool flag = false;//flag为true时表示推算完成,结束递归
bool check(int n){//判断当前位置的值是否满足条件
int h = n / 9;//行号
int l = n % 9;//列号
for (int i = 0; i < 9; ++i){//同一列中不能有重复
if (i != h && num[i][l] == num[h][l]){
return false;
}
}
for (int j = 0; j < 9; ++j){//同一行中不能有重复
if (j != l && num[h][j] == num[h][l]){
return false;
}
}
for (int i = h / 3 * 3; i < h / 3 * 3 + 3; ++i){//九宫格内不重复
for (int j = l / 3 * 3; j < l / 3 * 3 + 3; ++j){
if ((i != h || j != l) && num[i][j] == num[h][l]){
return false;
}
}
}
return true;
}
void dfs(int n)
{
if (n == 81){//如果已经递归到右下角,输出整个盘面,并置flag为true,结束递归
for (int i = 0; i < 9; ++i){
for (int j = 0; j < 8; ++j){
cout << num[i][j] << ' ';
}
cout << num[i][8] << endl;
}
flag = true;
return;
}
int h = n / 9;//行号
int l = n % 9;//列号
if (num[h][l] == 0){//如果当前位置为0,说明需要推算
for (int i = 1; i <= 9; ++i){//枚举1-9的数字,判断哪个满足条件
num[h][l] = i;
if (check(n)){//判断当前数字是否满足条件
dfs(n + 1);//如果满足条件继续往下递归
if (flag){//如果flag为true表示整个盘面的递归结束了
return;
}
}
}
num[h][l] = 0;//需要回溯,恢复num[h][l]的值为0
}else{//当前位置不为0,往下一格递归
dfs(n + 1);
}
}
int main()
{
for (int i = 0; i < 9; ++i){
for (int j = 0; j < 9; ++j){
cin >> num[i][j];//输入9x9盘面
}
}
dfs(0);//从左上角开始递归
return 0;
}
方法二:
#include <iostream>
using namespace std;
int num[9][9];//用于保存9x9盘面
int row[9][9]={0};
int col[9][9]={0};
int block[3][3][9]={0};
bool flag = false;//flag为true时表示推算完成,结束递归
bool check(int n,int num){//判断当前位置的值是否满足条件
int h = n / 9;//行号
int l = n % 9;//列号
if(row[h][num-1] == 1||col[l][num-1] == 1|| block[h/3][l/3][num-1]==1){
return false;
}
return true;
}
void dfs(int n){
if (n == 81){//如果已经递归到右下角,输出整个盘面,并置flag为true,结束递归
for (int i = 0; i < 9; ++i){
for (int j = 0; j < 8; ++j){
cout << num[i][j] << ' ';
}
cout << num[i][8] << endl;
}
flag = true;
return;
}
int h = n / 9;//行号
int l = n % 9;//列号
if (num[h][l] == 0){//如果当前位置为0,说明需要推算
for (int i = 1; i <= 9; ++i){//枚举1-9的数字,判断哪个满足条件
num[h][l] = i;
if (check(n,i)){//判断当前数字是否满足条件
//更新每行、每列、每九宫格值的信息
row[h][i-1] = 1;
col[l][i-1] = 1;
block[h/3][l/3][i-1] = 1;
dfs(n + 1);//如果满足条件继续往下递归
if (flag){//如果flag为true表示整个盘面的递归结束了
return;
}
//回溯
row[h][i-1] = 0;
col[l][i-1] = 0;
block[h/3][l/3][i-1] = 0;
}
}
num[h][l] = 0;//需要回溯,恢复num[h][l]的值为0
}else{//当前位置不为0,往下一格递归
dfs(n + 1);
}
}
int main()
{
for (int i = 0; i < 9; ++i){
for (int j = 0; j < 9; ++j){
int temp;
cin >> num[i][j];//输入9x9盘面
temp = num[i][j];
if(temp!=0){//记录每行、每列、每九宫格值的信息
row[i][temp-1] = 1;
col[j][temp-1] = 1;
block[i/3][j/3][temp-1] = 1;
}
}
}
dfs(0);//从左上角开始递归
return 0;
}
方法二:递归空间优化(位运算)
#include<iostream>
#include<vector>
using namespace std;
vector<vector<int> > sudoku(9, vector<int>(9, 0)); //记录数独矩阵
vector<int> col(9, 0); //用数字记录每列1-9是否有被使用过
vector<int> row(9, 0); //用数字记录每行1-9是否有被使用过
vector<vector<int> > block(3, vector<int>(3, 0)); //用数字记录每个方块1-9是否有被使用过
vector<pair<int, int> > space; //记录空缺的位置
void flip(int i, int j, int num){ //将第num位由0变成1或者由1变回0
row[i] ^= (1 << num);
col[j] ^= (1 << num);
block[i / 3][j / 3] ^= (1 << num);
}
void dfs(int pos, bool& valid){ //dfs搜索每一种情况
if(pos == space.size()){ //填充到空缺结尾,结束
valid = true;
return;
}
auto p = space[pos];
for(int i = 0; i < 9 && !valid; i++){ //遍历1-9,尝试每个数字
int mask = 1 << i; //找打第i位
//后续三个第i位都不能为1才代表可以使用该数字
if(!(mask & row[p.first]) && !(mask & col[p.second]) && !(mask & block[p.first / 3][p.second / 3])){
flip(p.first, p.second, i); //第i位置为1
sudoku[p.first][p.second] = i + 1;
dfs(pos + 1, valid); //递归找下一个
flip(p.first, p.second, i); //回溯
}
}
}
int main(){
for(int i = 0; i < 9; i++)
for(int j = 0; j < 9; j++){ //输入矩阵
cin >> sudoku[i][j];
if(sudoku[i][j] == 0) //如果缺少,坐标加入缺少的数组
space.push_back(make_pair(i, j));
else{ //否则行列块都记录这个数字出现过了
int num = sudoku[i][j];
flip(i, j, num - 1);
}
}
bool valid = false;
dfs(0, valid);
for(int i = 0; i < 9; i++){ //输出
for(int j = 0; j < 9; j++){
cout << sudoku[i][j] << " ";
}
cout << endl;
}
return 0;
}
HJ45 名字的漂亮度
描述
给出一个字符串,该字符串仅由小写字母组成,定义这个字符串的“漂亮度”是其所有字母“漂亮度”的总和。
每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个不同字母拥有相同的“漂亮度”。字母忽略大小写。
给出多个字符串,计算每个字符串最大可能的“漂亮度”。
本题含有多组数据。
数据范围:输入的名字长度满足 1≤n≤10000
输入描述:
第一行一个整数N,接下来N行每行一个字符串
输出描述:
每个字符串可能的最大漂亮程度
/*
解题思路:笨方法——用「钱」式思维来思考
名字的漂亮度,其实就是比谁的名字更值钱!
我们将名字的字母对应的「数字」作为它的价钱,
比如 26 最高,1 则最低,按大小顺序排布。
那么,我们要得到名字的最大可能「漂亮度」,
就要使得,越高频出现的字母,价钱越高。
Better than OK? 来!我们一起开始写代码!
*/
#include <iostream>
#include <algorithm>
using namespace std;
//计算名字的最大可能漂亮度(最高价钱)的函数接口
int MostValuableName (string Name) {
int Alphabet[26] = {0}; //初始化一个数组,用于记录名字中不同字母出现的次数
int Price[26] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}; //初始化一个价钱表
int MostValuable = 0; //初始化名字的最高价钱
for (int i = 0; i < Name.size(); i++) {
//大写字母的情况
if (Name[i] >= 'A' && Name[i] <= 'Z') {
Alphabet[Name[i] - 'A'] += 1; //累加字母的出现次数
}
//小写字母的情况
else if (Name[i] >= 'a' && Name[i] <= 'z') {
Alphabet[Name[i] - 'a'] += 1; //累加字母的出现次数
}
}
sort(Alphabet, Alphabet + 26);
for (int i = 0; i < 26; i++) {
MostValuable += Alphabet[i] * Price[i]; //依次取高频字母,对应地,依次取高价钱;
//正所谓「好货不便宜,便宜无好货」,哦,好像不对,
//应该是卖得越多的货的价钱越高,就越赚钱!!!
}
return MostValuable; //返回一个名字的最大可能价钱(即漂亮度)
}
//计算多个名字的最大可能漂亮度(最高价钱)的函数接口
int MaximumPriceOfName (int Number) {
string Name; //字符串形式的名字
for (int i = 0; i < Number; i++) {
cin >> Name; //输入名字
cout << MostValuableName (Name) << endl; //输出名字的最大可能漂亮度
}
return 0;
}
//主函数
int main () {
int N; //需要计算最大可能漂亮的名字个数
while (cin >> N) {
MaximumPriceOfName (N); //输出多个名字的最大可能漂亮度
}
return 0;
}
HJ46 截取字符串
描述
输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出
数据范围:字符串长度满足 1≤n≤1000 , 1≤k≤n
输入描述:
1.输入待截取的字符串
2.输入一个正整数k,代表截取的长度
输出描述:
截取后的字符串
方法一:substr()
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
int k;
while(cin>>str>>k){//输入字符串和k
string sub_str = str.substr(0,k);
cout<<sub_str<<endl;//输出前k个字符
}
}
方法二:遍历
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
int k;
while(cin>>str>>k){//输入字符串和k
for(int i = 0;i < k;i++){//遍历一遍字符串,输出前k个字符
cout<<str[i];
}
cout<<endl;
}
}
HJ48 从单向链表中删除指定值的节点
方法一:数组模拟
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int n, head;
while(cin >> n >> head){
vector<int> array; //用数组模拟链表
array.push_back(head);
for(int i = 1; i < n; i++){
int num, pos_num;
cin >> num >> pos_num; //输入要插入的数和它要插入哪个数字后面
auto iter = find(array.begin(), array.end(), pos_num); //找到要插入后面你的那个位置
if(iter == array.end()) //结尾push_back
array.push_back(num);
else //中间insert
array.insert(iter + 1, num);
}
int remove;
cin >> remove;
array.erase(find(array.begin(), array.end(), remove)); //找到要移除的数字的位置
for(int i = 0; i < array.size(); i++) //输出
cout << array[i] << " ";
cout << endl;
}
return 0;
}
方法二:链表
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node{ //链表结点
int val;
struct node* next = NULL;
};
int main(){
int n, val;
while(cin >> n >> val){
node* head = new node; //头结点
head->val = val;
for(int i = 1; i < n; i++){
int pre, cur;
cin >> cur >> pre;
node* p = new node; //添加这个结点
p->val = cur;
node* q = head;
while(q->val != pre) //找到前序结点
q = q->next;
p->next = q->next; //断开
q->next = p; //插入
}
int remove;
cin >> remove;
node* p = head;
while(p != NULL){
if(p->val != remove) //不输出remove,其他都输出
cout << p->val << " ";
p = p->next;
}
cout << endl;
}
return 0;
}
HJ50 四则运算
描述
输入一个表达式(用字符串表示),求这个表达式的值。
保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。
数据范围:表达式计算结果和过程中满足 ∣val∣≤1000 ,字符串长度满足 1≤n≤1000
输入描述:
输入一个算术表达式
输出描述:
得到计算结果
方法一:递归
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int compute(string& s, int left, int right){
char op = '+'; //默认加开始
int num = 0;
vector<int> st;
for(int i = left; i <= right; i++){
if(isdigit(s[i])) //数字
num = num * 10 + s[i] - '0'; //计算该部分数字总和
if(s[i] == '{' || s[i] == '[' || s[i] == '('){ //进入左括号
int layer = 0; //统计左括号层数
int j = i;
while(j <= right){ //遍历到右边
if(s[j] == '{' || s[j] == '[' || s[j] == '(')
layer++; //遇到左括号,层数累加
else if(s[j] == '}' || s[j] == ']' || s[j] == ')'){
layer--; //遇到右括号层数递减
if(layer == 0) //直到层数为0
break;
}
j++;
}
num = compute(s, i + 1, j - 1); //递归计算括号中的部分
i = j + 1;
}
if(!isdigit(s[i]) || i == right){ //遇到运算符或者结尾
switch(op){ //根据运算符开始计算
case '+': st.push_back(num); break; //加减法加入到末尾
case '-': st.push_back(-num); break;
case '*': st.back() *= num; break; //乘除法与末尾计算
case '/': st.back() /= num; break;
}
op = s[i]; //修改为下一次的运算符
num = 0;
}
}
int res = 0;
for(int x : st) //累加和
res += x;
return res;
}
int main(){
string s;
while(cin >> s){
cout << compute(s, 0, s.length() - 1) << endl;
}
return 0;
}
方法二:双栈法
#include<iostream>
#include<stack>
using namespace std;
void compute(stack<int>& st1, stack<char>& st2){ //根据栈顶运算符弹出栈顶两个元素进行运算
int b = st1.top();
st1.pop();
int a = st1.top();
st1.pop();
char op = st2.top(); //栈顶运算符
st2.pop();
if(op == '+') a = a + b; //加
else if(op == '-') a = a - b; //减
else if(op == '*') a = a * b; //乘
else if(op == '/') a = a / b; //除
st1.push(a);
}
bool priority(char m, char n){ //比较运算符优先级
if(m == '(') //括号优先级最高
return false;
else if((m == '+' || m == '-') && (n == '*' || n == '/')) //加减法小于乘除法
return false;
return true;
}
int main(){
string s;
while(cin >> s){
stack<int> st1; //记录运算数字
stack<char> st2; //记录运算符
st2.push('('); //整个运算式添加括号
s += ')';
bool flag = false;
for(int i = 0; i < s.length(); i++){
if(s[i] == '(' || s[i] == '[' || s[i] == '{') //如果是左括号都在运算符栈加入(
st2.push('(');
else if(s[i] == ')' || s[i] == ']' || s[i] == '}'){ //遇到右括号
while(st2.top() != '('){ //弹出开始计算直到遇到左括号
compute(st1, st2);
}
st2.pop(); //弹出左括号
} else if(flag){ //运算符
while(priority(st2.top(), s[i])){ //比较运算优先级
compute(st1, st2); //可以直接计算
}
st2.push(s[i]); //需要将现阶段加入栈中等待运算
flag = false;
} else{ //数字
int j = i; //记录起始
if(s[j] == '-' || s[j] == '+') //正负号
i++;
while(isdigit(s[i])){
i++;
}
string temp = s.substr(j, i - j);
st1.push(stoi(temp)); //截取数字部分,转数字
i--;
flag = true; //数字结束,下一次flag为true就是运算符了
}
}
cout << st1.top() << endl; //输出
}
return 0;
}
HJ51 输出单向链表中倒数第k个结点
描述
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。
链表结点定义如下:
struct ListNode { int m_nKey; ListNode* m_pNext; };
正常返回倒数第k个结点指针,异常返回空指针.
要求:
(1)正序构建链表;
(2)构建后要忘记链表长度。
数据范围:链表长度满足 1≤n≤1000 ,k≤n ,链表中数据满足0≤val≤10000
本题有多组样例输入。
输入描述:
输入说明
1 输入链表结点个数
2 输入链表的值
3 输入k的值
输出描述:
输出一个整数
方法一:根据长度找倒数k
#include<iostream>
using namespace std;
struct ListNode{ //链表结点
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL){} //初始化
};
ListNode* FindKthToTail(ListNode* pHead, int k, int n) { //找到链表倒数第k个结点
ListNode* p = pHead;
if(n < k) //长度过小,返回空链表
return p = NULL;
for(int i = 0; i < n - k; i++) //遍历n-k次
p = p->next;
return p;
}
int main(){
int n;
while(cin >> n){ //输入n
int val;
cin >> val;
ListNode *head = new ListNode(val); //链表第一个结点
ListNode *p = head;
for(int i = 1; i < n; i++){ //输入链表后续结点
cin >> val;
ListNode *q = new ListNode(val);
p->next = q; //连接
p = p->next;
}
int k;
cin >> k; //输入k
if(k == 0) //k等于0直接输出0
cout << 0 << endl;
else{
p = FindKthToTail(head, k, n); //找到第k个结点
if(p != NULL) //返回不为null才能输出
cout << p->val << endl;
}
}
return 0;
}
方法二:快慢双指针
#include<iostream>
using namespace std;
struct ListNode{ //链表结点
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL){} //初始化
};
ListNode* FindKthToTail(ListNode* pHead, int k) {//找到链表倒数第k个结点
int n = 0;
ListNode* fast = pHead;
ListNode* slow = pHead;
for(int i = 0; i < k; i++){ //快指针先行k步
if(fast != NULL)
fast = fast->next;
else //达不到k步说明链表过短,返回空链表
return slow = NULL;
}
while(fast != NULL){ //快慢指针同步,快指针先到底,慢指针指向倒数第k个
fast = fast->next;
slow = slow->next;
}
return slow;
}
int main(){
int n;
while(cin >> n){ //输入n
int val;
cin >> val;
ListNode *head = new ListNode(val); //链表第一个结点
ListNode *p = head;
for(int i = 1; i < n; i++){ //输入链表后续结点
cin >> val;
ListNode *q = new ListNode(val);
p->next = q; //连接
p = p->next;
}
int k;
cin >> k; //输入k
if(k == 0) //k等于0直接输出0
cout << 0 << endl;
else{
p = FindKthToTail(head, k); //找到第k个结点
if(p != NULL) //返回不为null才能输出
cout << p->val << endl;
}
}
return 0;
}