卡码网训练(ACM模式)-代码随想录

一.数组

卡码网33.逛街

思路一:

                1.先将输入字符转换为int数组
                2.使用栈从0遍历数组,保存第i位之前可以连续降序的数值
                3.使用栈从n-1遍历数组,保存第i位之后可以连续降序的数值
                4.及时更新第i个位置前后存在的到达i之前连续降序的数值个数
#include <iostream>
#include <vector>
#include <sstream>
#include <stack>
#include <algorithm>
using namespace std;
vector<int> parseIntArray(string input) {//获取高度数组
    vector<int> parsedArray;
    stringstream ss(input.substr(1, input.length() - 2));//使用字符串流stringstream处理输入字符串,并把头尾的括号去掉
    string item;
    while (getline(ss, item, ',')) {//使用getline从stringstream中按逗号分割获取每个字符串元素
        parsedArray.push_back(std::stoi(item));//将字符串元素转为数字
    }
    return parsedArray;
}

void calculateVisibleCounts(const vector<int>& heights, vector<int>& visibleCounts) {
    int n = heights.size();
    stack<int> stack1, stack2;

    for (int i = 0; i < n; i++) {//从左往右找(相当于看第i位左边符合条件的)
        visibleCounts[i] += stack1.size();//降序排列的数值,就是从当前位置起栈里的都能看到,当前位置的初始化已经加上
        while (!stack1.empty() && stack1.top() <= heights[i]) {//第i位元素是否大于等于前面的元素时,把前面的元素弹出
            stack1.pop();                                      //直到找到一个比当前元素大的值,或者栈空
        }                                                      //使得栈中的元素全是按降序排列的(从底到顶)
        stack1.push(heights[i]);//把当前位置加入
    }

    for (int i = n - 1; i >= 0; i--) {//从右往左找(相当于看第i位右边符合条件的
        visibleCounts[i] += stack2.size();//同理把从右往左能看到的都加上
        while (!stack2.empty() && stack2.top() <= heights[i]) {//等于的时候也要弹出,因为等于也看不见
            stack2.pop();//也是形成降序排列
        }
        stack2.push(heights[i]);
    }
}

int main() {
    string buildings;
    while(getline(cin, buildings)){
        vector<int> heights = parseIntArray(buildings);
        int n = heights.size();
        vector<int> visibleCounts(n, 1);//初始化都为1,因为在第i个位置上,必然能看到第i个位置
        calculateVisibleCounts(heights, visibleCounts);
        cout << "[";
        for (int i = 0; i < n; i++) {
            cout << visibleCounts[i];
            if (i < n - 1) 
                cout << ",";
        }
        cout << "]" <<endl;
    }
    
    
    
    // 输出可见建筑物数量
    

    return 0;
}

卡码网13.镂空三角形

思路:根据题意,可以把结果分成四个部分
                1.打印空格(空格的数量是递减的,且最后一行不需要)
                2.打印字符(相当于左侧字符,前n-1行都只需打印一个,最后一行需打印n个)
                3.打印空格(属于中间空格,发现符合2*i-1的规律递增,最后一行无需打印)
                4.打印字符(相当于右侧字符,第一行无需打印,2到n-1行打印一个,最后一行打印n-1个
#include<iostream>
#include<sstream>
using namespace std;
int main() {
    string str;
    while (getline(cin, str)) {
        stringstream ss(str);
        char midC;
        
        int midI;
        ss >> midC;
        if (midC == '@')
            break;
        ss >> midI;
        for (int i = 0; i < midI; i++) {
            //打印空格
            int midP = midI - i-1;
            while (midP--)
                cout << ' ';
            //打印字符
            int midS = midI;
            if (i != midI - 1)
                cout << midC;
            else {
                while (midS--)
                    cout << midC;
            }
            //打印空格
            if (i != midI - 1 && i!=0) {
                int midC1 = 2 * i-1 ;
                while (midC1--)
                    cout << ' ';
            }
            
            //打印字符
            if (i == 0) {
                cout << endl;
                continue;

            }
                
            int midC2 = midI;
            if (i != midI - 1)
                cout << midC;
            else {
                midC2--;
                while (midC2--)
                    cout << midC;
            }
            cout << endl;
        }
        cout << endl;
    }
    return 0;
}

 二.字符串

卡码网14.句子缩写

思路一:直接使用字符串流接收数据,然后赋给string
注意:使用cin获取n之后需要使用getchar() 吸收一个回车,因为第一行只需要一个n
#include<iostream>
#include<sstream>
using namespace std;

int main() {
    int n;
    cin>>n;
    getchar();
    string str;
    while (n--) {
        getline(cin, str);
        string res;
        stringstream ss(str);
        string mid;
        while (ss >> mid) {
            //大写字母65-90 小写字母97-122
            if (mid[0] - 'a' >= 0)//为小写字母
                res.push_back(mid[0] - 32);
            else
                res.push_back(mid[0]);
        }
        cout << res << endl;
    }
    return 0;
}

卡玛网15.神秘字符

思路:使用双指针把第一个字符的后半部分往后移,腾出第二个字符的位置
#include<iostream>
using namespace std;
string displayString(string& first,string& second){
    int lenF=first.size();
    int lenS=second.size();
    first.resize(lenF+lenS);
    int left=lenF-1,right=lenF+lenS-1;//相当于把后一半的字符移动到后面,腾出second的位置
    while(left>=(lenF/2)){
        first[right--]=first[left--];
    }
    for(auto it:second){
        first[++left]=it;
    }
    return first;
}
int main(){
    int n;
    cin>>n;
    getchar();
    while(n--){
        string fisrt;
        getline(cin,fisrt);
        string second;
        getline(cin,second);
        cout<<displayString(fisrt,second)<<endl;
    }
    return 0;
}

卡码网16.位置交换

思路:简单的奇偶交换,使用双指针指向,然后每次递增2
#include<iostream>
using namespace std;
int main(){
    int n;
    cin>>n;
    getchar();
    while(n--){
        string str;
        getline(cin,str);
        int i=0,j=1;
        while(i<str.size()-1 && j<str.size()){
            char temp=str[i];
            str[i]=str[j];
            str[j]=temp;
            i+=2;
            j+=2;
        }
        
        cout<<str<<endl;
        
    }
    
    
    return 0;
}

三.栈和队列

卡码网17.出栈合法性

思路:
遍历每一个出栈的数字,遍历到i时,就判断栈中是否入栈到i。
1.还没有入栈到i,先入栈到i,此时出栈合法
2.已经入栈到i后面,判断栈顶元素是否等于出栈元素
  • 等于时出栈合法
  • 不等于时出栈不合法
#include<iostream>
#include<stack>
#include<sstream>
using namespace std;

int main() {
    int n;
    while (cin >> n) {
        if (n == 0)
            break;
        getchar();//换到下一行
        string str;
        getline(cin, str);
        stringstream ss(str);
        int outNum, intNum = 1;//出栈和入栈下标
        stack<int> st;
        bool judge = true;//判断是否出栈成功
        while (ss >> outNum) {
            //cout << outNum << endl;
            while (outNum >= intNum) {
                st.push(intNum++);
            }
            //出栈
            //cout << st.top() << endl;
            if (st.top() == outNum)//当前元素可以出栈成功
                st.pop();
            else {//当前元素无法出栈
                judge = false;
                break;
            }
        }
        if (!judge)
            cout << "No" << endl;
        else
            cout << "Yes" << endl;
    }
    return 0;
}

四.链表

卡码网18.链表的基本操作

问题:本地编译器和运行都没问题,但是提交之后(show和delete)会多出空格

#include<iostream>
#include<string>
#include<sstream>
#include<vector>
#include<stack>
using namespace std;

struct TreeNode {
    int val;
    TreeNode* next;
    TreeNode() {
        val = 0;
        next = nullptr;
    }
    TreeNode(int _val) {
        val = _val;
        next = nullptr;
    }
};
TreeNode* newRoot = new TreeNode();
int List_size = 0;
string get(TreeNode* root, int index) {//获取指定位置元素
    if (index > List_size)
        return "get fail";
    TreeNode* cur = root;
    while (--index) {
        if (cur->next)
            cur = cur->next;
        else
            return "get fail";
    }
    return to_string(cur->val);
}

TreeNode* insert(TreeNode* root, int index, int val) {//在指定位置之前插入元素
    if (index == 1) {
        TreeNode* node = new TreeNode(val);
        node->next = newRoot->next;
        newRoot->next = node;
        cout << "insert OK";
        List_size++;
        return node;
    }
    if (index <= 0 || index > List_size) {
        cout << "insert fail";
        return root;
    }
    TreeNode* node = new TreeNode(val);
    TreeNode* pre = newRoot, * cur = root;
    while (--index) {
        if (cur->next) {
            pre = cur;
            cur = cur->next;
        }
        else {
            cout << "insert fail";
            return root;
        }
    }
    node->next = pre->next;
    pre->next = node;
    cout << "insert OK";
    List_size++;
    return newRoot->next;
}
TreeNode* deleteNode(TreeNode* root, int index) {//删除指定位置的元素
    if (index <= 0 || index > List_size) {
        cout << "delete fail";
        return root;
    }
    TreeNode* pre = newRoot, * cur = root;
    while (--index) {
        if (cur->next) {
            pre = cur;
            cur = cur->next;
        }
        else {
            cout << "delete fail";
            return root;
        }
    }
    if (cur->next)
        pre->next = cur->next;
    else
        pre->next = nullptr;
    cur = nullptr;
    cout << "delete OK";
    List_size--;
    return newRoot->next;
}
void showNodes(TreeNode* root) {//打印链表中所有元素
    if (List_size == 0){
        cout << "Link list is empty";
        return;
    }
        
    TreeNode* cur = root;
    while (cur) {
        cout << cur->val;
        if (cur->next)
            cout << " ";
        cur = cur->next;
    }
}
int main() {
    TreeNode* cur = newRoot;
    int n, midNum;
    cin >> n;
    stack<int>st;
    while (n--) {//初始化链表
        cin >> midNum;
        st.push(midNum);
    }
    List_size = st.size();
    while (!st.empty()) {
        TreeNode* node = new TreeNode(st.top());
        st.pop();
        cur->next = node;
        cur = node;
    }
    getchar();//换行
    cin >> n;
    getchar();
    int index, val;
    while (n--) {
        string mid;
        cin >> mid;
        
        if (mid == "get")
        {
             cin >> index;
             cout << get(newRoot->next, index);
        }
        else if (mid == "insert")
		{
            cin >> index;
            cin >> val;
            newRoot->next = insert(newRoot->next, index, val);
        }
        else if (mid == "delete") {
            cin >> index;
            newRoot->next = deleteNode(newRoot->next, index);
        }
        else if (mid == "show") {
            showNodes(newRoot->next);
        }
        cout << endl;
     }
    return 0;
}

卡码网19.单链表反转

思路:创建,递归反转
#include<iostream>
using namespace std;

struct ListNode {
    int val;
    ListNode* next;
    ListNode() {
        val = 0;
        next = nullptr;
    }
    ListNode(int _val) {
        val = _val;
        next = nullptr;
    }
};
ListNode* newHead = new ListNode(1);

ListNode* judge(ListNode* root) {
    if (root->next == nullptr) return root;
    ListNode* newRoot = judge(root->next);
    root->next->next = root;
    root->next = nullptr;
    return newRoot;
}
void display(ListNode* root) {
    ListNode* cur = root;
    while (cur) {
        cout << cur->val;
        if (cur->next)
            cout << " ";
        cur = cur->next;
    }
}
int main() {
    ListNode* cur = newHead;
    int n;
    while (cin >> n) {
        if (n == 0) {
            cout << "list is empty" << endl;
            continue;
        }
        int midNum;
        while (n--) {//构建链表
            cin >> midNum;
            //cout << midNum;
            ListNode* node = new ListNode(midNum);
            cur->next = node;
            cur = node;
        }
        ListNode* head = newHead->next;
        
        ListNode* n1 = head;
        newHead = nullptr;
        delete newHead;
        //display(head);
        head=judge(head);
        display(head);
        cout << endl;
    }


    return 0;
}

20.删除重复元素

 思路:双指针

#include<iostream>
using namespace std;
struct ListNode {
    int val;
    ListNode* next;
    ListNode() {
        val = 0;
        next = nullptr;
    }
    ListNode(int _val) {
        val = _val;
        next = nullptr;
    }
};

void display(ListNode* root) {
    ListNode* cur = root;
    while (cur) {
        cout << cur->val;
        if(cur->next)
            cout<<" ";
        cur = cur->next;
    }
    cout << endl;
}

void deleteNode(ListNode* root) {
    ListNode* p = root, * cur = root->next;
    while (cur) {
        if (p->val == cur->val) {
            if (cur->next) {
                p->next = cur->next;
                cur = p->next;
            }
            else {
                p->next = nullptr;
                cur=nullptr;
            }
        }
        else {
            p = cur;
            cur = cur->next;
        }
    }
}
int main() {
    int n;
    while (cin >> n) {
        if (n == 0){
            cout<<"list is empty";
            break;
        }
        ListNode* head = new ListNode(0);
        ListNode* pre = head;
        int midNum;
        while (n--) {//创建链表
            cin >> midNum;
            ListNode* node = new ListNode(midNum);
            pre->next = node;
            pre = node;
        }
        display(head->next);
        deleteNode(head);
        display(head->next);
    }
    return 0;
}

五.二叉树 

卡码网21.构造二叉树

思路一:根据前序遍历找出中间节点,然后把两个字符串切割递归遍历
#include<iostream>
#include<sstream>
using namespace std;
struct TreeNode {
    char val;
    TreeNode* left;
    TreeNode* right;
    TreeNode() {
        val = 0;
        left = nullptr;
        right = nullptr;
    }
    TreeNode(int _val) {
        val = _val;
        left = nullptr;
        right = nullptr;
    }
};

TreeNode* buildTree(string& PreSort, string& MidSort) {
    if (PreSort.size() == 0) return nullptr;
    int midValue = PreSort[0];
    TreeNode* midNode = new TreeNode(midValue);//中间节点
    //找到中间节点下标
    int midIndex = 0;
    while (MidSort[midIndex] != midValue)
        midIndex++;
    //分割中序数组(左闭右开)
    string leftMidSort(MidSort.begin(), MidSort.begin() + midIndex);
    string rightMidSort(MidSort.begin() + midIndex + 1, MidSort.end());

    //分割前序数组(左闭右开)
    string leftPreSort(PreSort.begin() + 1, PreSort.begin() + leftMidSort.size() + 1);
    string rightPreSort(PreSort.begin() + leftMidSort.size() + 1, PreSort.end());

    midNode->left = buildTree(leftPreSort, leftMidSort);
    midNode->right = buildTree(rightPreSort, rightMidSort);

    return midNode;

}
void display(TreeNode* root) {
    if (root == nullptr) return;
    display(root->left);
    display(root->right);
    cout << root->val;
}
int main() {
    string str;
    while (getline(cin, str)) {
        stringstream ss(str);
        string PreSort, MidSort;
        ss >> PreSort >> MidSort;
        TreeNode* root = buildTree(PreSort, MidSort);
        display(root);
        cout << endl;
    }
    return 0;
}

卡码网22.二叉树的遍历

思路:使用make_pair组合左右节点的下标对应的字符
#include<iostream>
#include<vector>
#include<unordered_map>
#include<sstream>
using namespace std;

struct TreeNode{
    char val;
    TreeNode*left;
    TreeNode*right;
    TreeNode(char _val){
        val=_val;
        left=nullptr;
        right=nullptr;
    }
};
//节点连接
TreeNode* connectTree(unordered_map<char, pair<char, char>>& nodeMap, char rootValue){
     if (rootValue == '0') {
        return nullptr;
    }

    TreeNode* root = new TreeNode(rootValue);
    int leftChild = nodeMap[rootValue].first;
    int rightChild = nodeMap[rootValue].second;

    root->left = connectTree(nodeMap, leftChild);
    root->right =connectTree(nodeMap, rightChild);

    return root;
}
//遍历
void predisplay(TreeNode*root){
    if(root==nullptr) return;
    cout<<root->val;
    predisplay(root->left);
    predisplay(root->right);
}
void middisplay(TreeNode*root){
    if(root==nullptr) return;
    middisplay(root->left);
    cout<<root->val;
    middisplay(root->right);
}
void lastdisplay(TreeNode*root){
    if(root==nullptr) return;
    lastdisplay(root->left);
    lastdisplay(root->right);
    cout<<root->val;
}
int main(){
    int n;
    cin >> n;
    unordered_map<char, pair<char, char>> nodeMap;

    // 先保存输入的数据 
    vector<char> index = vector<char>(n + 1, '0'); //保存坐标
    vector<vector<int>> nums = vector<vector<int>>(n + 1, vector<int>(2, 0));
    for (int i = 1; i <= n; i++) {
        cin >> index[i] >> nums[i][0] >> nums[i][1];
    }

    // 生成二叉树 
    for (int i = 1; i <= n; i++) {
        nodeMap[index[i]] = make_pair(index[nums[i][0]], index[nums[i][1]]);
    }
    TreeNode*root=connectTree(nodeMap, index[1]);
    predisplay(root);
    cout<<endl;
    middisplay(root);
    cout<<endl;
    lastdisplay(root);
    cout<<endl;
    return 0;
}

卡码网23.二叉树的高度

思路一:截取区间创建二叉树,遍历二叉树获取高度
#include<iostream>
using namespace std;

struct TreeNode {
    char val;
    TreeNode* left;
    TreeNode* right;
    TreeNode() :val(0), left(nullptr), right(nullptr) {};
    TreeNode(int _val) :val(_val), left(nullptr), right(nullptr) {};
};
TreeNode* buildTree(string& strPre, string& strMid) {
    if (strPre.size() == 0) return nullptr;

    int midValue = strPre[0];

    int midIndex = 0;//获取中间节点的下标
    while (strMid[midIndex] != midValue)
        midIndex++;
    //创建中间节点
    TreeNode* root = new TreeNode(midValue);
    if (strPre.size() == 1) return root;

    //分割中序
    string leftMid(strMid.begin(), strMid.begin() + midIndex);
    string rightMid(strMid.begin() + midIndex+1, strMid.end());
    strPre.erase(strPre.begin());
    //分割前序
    string leftPre(strPre.begin(), strPre.begin() + leftMid.size());
    string rightPre(strPre.begin() + leftMid.size(), strPre.end());

    root->left = buildTree(leftPre, leftMid);
    root->right = buildTree(rightPre, rightMid);

    return root;
}
int heightMax = 0;
void sumheight(TreeNode* root, int height) {
    if (root == nullptr) return;
    heightMax = max(height, heightMax);
    sumheight(root->left, height + 1);
    sumheight(root->right, height + 1);
}
int main() {
    int n;
    while (cin >> n) {
        int midn = n;
        string strPre, strMid;
        char mid;
        while (n--) {
            cin >> mid;
            strPre.push_back(mid);
        }
        while (midn--) {
            cin >> mid;
            strMid.push_back(mid);
        }
        TreeNode* root = buildTree(strPre, strMid);
        sumheight(root, 1);
        cout << heightMax << endl;

    }




    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值