华为机考108题(c++)(41-51)

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;
}

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南叔先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值