奇偶半排序

设计算法将顺序线性表中的所有奇数集中到数组的左边,所有的偶数集中到数组的右边,要求算法的时间复杂度为O(n)。

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
    int n;
    while(cin>>n) {
        int a[n];
        for(int i=0; i<n; i++) cin>>a[i];
        for(int L=0,R=n-1;L<R;){
            while(a[L]&1) ++L;
            while((L<R)&&!(a[R]&1)) --R;
            if(L<R) swap(a[L++],a[R--]);
        }
        for(int i=0; i<n; i++) cout<<a[i]<<' ';
        cout<<endl;
    }
    return 0;
}
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
    int n;
    while(cin>>n) {
        int a[n];
        for(int i=0; i<n; i++) cin>>a[i];
        for(int i=0,j=0; i<n; i++)
            if(a[i]&1) swap(a[i],a[j++]);
        for(int i=0; i<n; i++) cout<<a[i]<<' ';
        cout<<endl;
    }
    return 0;
}

循环移动

设将n(n>1)个整数存放到一维数组R中。试设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(X0,X1,…,Xn-1)变换为(Xp,Xp+1,…,Xn-1,X0,X1,…,Xp-1)。

思路:逆序的逆序就是有序,可以通过提前完成一遍操作来“保护”部分元素使其不被乱序,从而完成部分整体交换。

void Swap(int *a, int *b){
    *a^=*b;
    *b^=*a;
    *a^=*b;
}
void Reverse(int a[], int L, int R) {
    int n=((R-L+1)>>1);
    for(int i=0; i<n; i++)
        Swap(&a[L+i],&a[R-i]);
}
void Solve(int a[], int n, int p) {
    Reverse(a, 0, p-1);
    Reverse(a, p, n-1);
    Reverse(a, 0, n-1);
}

进制转换

十进制数n 转换成其他进制

#include<iostream>
#include<stack>
#include<algorithm>
using namespace std;
int main() {
    int n,m;
    while(cin>>n>>m) {
        stack<int>st;
        while(n){
            st.push(n%m);
            n/=m;
        }
        while(!st.empty()){
            cout<<st.top();
            st.pop();
        }
        cout<<endl;
    }
    return 0;
}

这也太水了

栈 中缀转后缀

#include <bits/stdc++.h>
using namespace std;
int main() {
    map<char,int>level;
    level['+']=1;
    level['-']=1;
    level['*']=3;
    level['/']=3;
    level['(']=0;
    stack<char>op;
    string s;
    while(printf("请输入中缀表达式: \n"),cin>>s) {
        printf("后缀表达式为:\n");
        for(int i=0,n=s.length(); i<n; i++) {
            if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') {
                if(op.empty())  op.push(s[i]);
                else if(level[s[i]]>level[op.top()]) op.push(s[i]);
                else {
                    while(!op.empty()&&level[op.top()]>=level[s[i]]) cout<<op.top(),op.pop();
                    op.push(s[i]);
                }
            } else if(s[i]=='(') op.push('(');
            else if(s[i]==')') {
                while(op.top()!='(') cout<<op.top(),op.pop();
                op.pop();
            } else cout<<s[i];
        }
        while(!op.empty()) cout<<op.top(),op.pop();
        cout<<endl<<endl;
    }
    return 0;
}

思路:
从左到右开始扫描中缀表达式
遇到非运算符时,加入后缀表达式
遇到运算符时:

  1. 若为'(',入栈
  2. 若为')',则依次将栈中的运算符加入到后缀表达式中,直到出现'('为止,从栈中删除'('
  3. 若为除括号外的其它运算符,当优先级高于除'('以外的栈顶运算符时,直接入栈;
    否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,
    直到出现一个比它优先级低或者遇到了一个左括号为止。

后缀表达式计算

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
double getnum(string str) {
    int n=str.size();
    int pos=-1;
    double ans=0.0;
    for(int i=n-1; i>=0; --i) if(str[i]=='.') {
            pos=i;
            break;
        }
    if(pos==-1) for(ll i=n-1,j=1; i>=0; --i,j*=10) ans+=(str[i]-'0')*j;
    else {
        for(ll i=pos-1,j=1; i>=0; --i,j*=10) ans+=(str[i]-'0')*j;
        double j=0.1;
        for(int i=pos+1; i<n; i++,j*=0.1) ans+=(str[i]-'0')*j;
    }
    return ans;
}
int main() {
    string s;
    while(getline(cin,s)){
    stack<double>st;
    double ans=0;
    bool vis=0;
    for(int i=0,n=s.size(),t; i<n; i++) {
        if(s[i]>='0'&&s[i]<='9') {
            for(t=i; i<n&&((s[i]>='0'&&s[i]<='9')||s[i]=='.'); ++i) ;
            double num=getnum(s.substr(t,i-t));
            st.push(num);
        } else if(s[i]=='+') {
            if(!vis) ans=st.top(),st.pop(),vis=1;
            double a=st.top();
            st.pop();
            ans=a+ans;
        } else if(s[i]=='-') {
            if(!vis) {
                double b=st.top();
                st.pop();vis=1;
                double a=st.top();
                st.pop();
                ans=a-b;
            }else {
                double a=st.top();
                st.pop();
                ans=ans-a;
            }
        } else if(s[i]=='*') {
            if(!vis) ans=st.top(),st.pop(),vis=1;
            double a=st.top();
            st.pop();
            ans=ans*a;
        } else if(s[i]=='/') {
            if(!vis) {
                double b=st.top();
                st.pop();vis=1;
                double a=st.top();
                st.pop();
                ans=a/b;
            }else {
                double a=st.top();
                st.pop();
                ans=ans/a;
            }
        }
    }
    cout<<ans<<endl;
    }
    return 0;
}

下面的是杨文冠的代码(数组倒着用就是了……

#include<bits/stdc++.h>
using namespace std;
int main() {
    char str[500];
    int cnt=10,top=0;
    float num=0,num1=0,s[500];
    scanf("%[^\n]",str);                //读入含空格的模板,直接scanf是做不到的 
    for(int i=0;str[i]!='#';) {            //遍历 
        if(str[i]>='0'&&str[i]<='9')    //如果是数字就转为整数(小数点前面的数就是整数) 
            num=num*10+str[i++]-'0';
        else if(str[i]=='.') while(str[++i]!=' ') {    //小数点前面的整数加上小数点后面的小数就是这个小数的值了 
                num+=(float)(str[i]-'0')/cnt;
                cnt*=10;
        }
        else if(str[i]==' ') {            //如果当前位置是空格 
            if(str[i-1]>='0'&&str[i-1]<='9') {    //如果前面输入了数字,就进栈并且初始化 
                s[top++]=num;
                num=0;
                cnt=10;
            }
            ++i;
        }
        else {                            //出栈进行计算,先出栈的是被操作数(即num1) 
            num1=s[--top];                //--top起到删除栈顶元素的作用 
            num =s[--top];
            switch(str[i++]) {
                case '+': num+=num1;    break;
                case '-': num-=num1;    break;
                case '*': num*=num1;    break;
                case '/': num/=num1;    break;
            }
            s[top++]=num;                //得到的新数进栈 
            num=0;
        }
    }
    cout<<s[0]<<endl;                    //运算结束后只有一个数
    return 0;
}

出栈序列

递归,二进制枚举

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int num = 0,n;
void f(vector<bool>pos, int cnt[], int a[]) {
    if (cnt[1]) {
        pos.push_back(1);
        --cnt[1];
        f(pos, cnt, a);
        ++cnt[1];
        pos.pop_back();
    }
    if (cnt[0] && cnt[0] > cnt[1]) {
        pos.push_back(0);
        --cnt[0];
        f(pos, cnt, a);
        ++cnt[0];
        pos.pop_back();
    }
    if (pos.size() == 2 * n) {
        stack<int>stk;
        int j = 0;
        for (vector<bool>::iterator it = pos.begin(); it != pos.end(); ++it) {
            if (*it) stk.push(a[j++]);
            else cout << stk.top() << " ", stk.pop();
        }
        ++num;
        cout << endl;
    }
}
int main() {
    while (cout << "Input the number: ", cin >> n) {
        int a[n];
        for (int i = 0; i < n; i++) a[i] = 1 + i;
        int cnt[2] = {n, n-1};
        vector<bool>pos;
        pos.push_back(1);
        f(pos, cnt, a);
        cout << "Total: " << num << endl;
        num = 0;
    }
    return 0;
}

全排列

#include <bits/stdc++.h>
using namespace std;
bool chk(vector<int> pushV, vector<int> popV) {
    stack<int>stk;
    for (int i=0,j=0; i < pushV.size(); ++i) {
        stk.push(pushV[i]);
        while (!stk.empty() && stk.top() == popV[j]) {
            stk.pop();
            ++j;
        }
    }
    return stk.empty();
}
int main() {
    int n;
    while(~scanf("%d", &n)) {
        vector<int> p, q;
        for (int i=1; i<=n; ++i) p.push_back(i), q.push_back(i);
        do {
            if (chk(q, p)) {
                for (auto i : p) printf("%d ",i);
                printf("\n");
            }
        } while (next_permutation(p.begin(), p.end()));
    }
    return 0;
}//全排列方案

链表倒数第k

已知一个带有表头结点的单链表,结点结构为(data,link),假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点(k为正整数)。若查找成功,算法输出该结点的data域的值,并返回1;否则,只返回0。要求:
(1)描述算法的基本设计思想;
(2)描述算法的详细实现步骤;
(3)根据设计思想和实现步骤,采用程序设计语言描述算法,关键之处请给出简要注释。

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
struct node {
    int data;
    struct node *link;
};
node *GetList() {
    node *head=NULL,*rear=NULL;
    printf("Input List, end with -1 :\n");
    int TmpVal=0;
    while(scanf("%d",&TmpVal),TmpVal!=-1) {
        node *TmpNode=(node *)malloc(sizeof(node));
        TmpNode->data=TmpVal;
        if (head==NULL) head=TmpNode;
        else rear->link=TmpNode;
        rear=TmpNode;
    }
    if (rear) rear->link=NULL;
    return head;
}
int main() {
    node *head=GetList();
    if (head==NULL) {
        printf("List is empty!\n");
        return 0;
    }
    //倒数第k==正数第n-k+1==n-(k-1)
    //指针i从头指针开始遍历,向前走k-1,指针j不动
    //i j同时向前移动 直到i到达n 此时j指向即为所求
    int k;
    while(printf("Input K : "),~scanf("%d",&k)) {
        node *i=head,*j=head;
        for(int cnt=1; cnt<=k&&i; ++cnt,i=i->link);
        for(; i; i=i->link,j=j->link);
        printf("The K-th last number is: %d\n\n",j->data);
    }
    return 0;
}

链表公共起始位

假定采用带头节点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,例如,“loading”和“being”,如下图所示。
图片说明
请设计一个时间上尽可能高效的算法,找出由str1和str2所指向两个链表共同后缀的起始位置(如图中字符i所在节点的位置p)。要求:
  (1)给出算法的基本设计思想。
  (2)根据设计思想,采用C或C++或JAVA语言描述算法,关键为之处给出注释。
  (3)说明你所设计算法的时间复杂度。

//将两个str以尾部为基准对齐,指针指向最小点
//两个指针同时右移,直到指向地址相同/指向NULL
//指向点即为所求
//O(m+n)线性阶

typedef struct Node{
    char data;
    struct Node *next;
} SNODE;
SNODE * Findlist(SNODE *str1,SNODE *str2){
  int m,n;
 SNODE *p,*q;
 m=Listlen(str1);  //求单链表str1的长度m
 n=Listlen(str2);  //求单链表str2的长度n
 for (p=str1;m>n;m--)  //若m大,则str1后移m-n个节点
  p=p->next;
 for (q=str2;m<n;n--)  //若n大,则str2后移n-m个节点
  q=q->next;
 while (p->next!=NULL && p->next!=q->next){ 
     p=p->next;                //p、q两步后移找第一个指针值相等的节点
   q=q->next;
     }
     return p->next;
}

链表排序-归并

链表的高效排序 O(nlogn)

#include<iostream>
#include<stack>
#include<string>
using namespace std;
ListNode* sortList(ListNode* head) {
    if(head==nullptr)
        return nullptr;
    if(head->next==nullptr)
        return head;
    ListNode *slow = head;                  //设置一个慢指针
    ListNode *fast = head->next;            //设置一个快指针
    while(fast!=nullptr) {                  //找出链表的中间节点
        fast = fast->next;
        if(fast==nullptr)
            break;
        fast = fast->next;
        slow = slow->next;
    }
    ListNode *list1 = head;
    ListNode *list2 = slow->next;
    slow->next = nullptr;
    ListNode *left = sortList(list1);       //递归左归并
    ListNode *right = sortList(list2);      //递归右归并
    ListNode *output = merge(left,right);   //合并两个有序链表
    return output;
}

//合并两个有序链表
ListNode* merge(ListNode *left, ListNode *right) {
    ListNode *out;
    if(left->val<right->val) {
        out = left;
        left = left->next;
    } else {
        out = right;
        right = right->next;
    }
    ListNode *p = out;
    p->next = nullptr;
    while(left&&right) {
        if(left->val<right->val) {
            p->next = left;
            left = left->next;
            p = p->next;
            p->next = nullptr;
        } else {
            p->next = right;
            right = right->next;
            p = p->next;
            p->next = nullptr;
        }
    }
    if(left!=nullptr)p->next = left;
    if(right!=nullptr)p->next = right;
    return out;
}

提取数字

从一个混有英文字母的字符串中提取数字。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    int a[105];
    int cnt = 0;
    char ch;
    do {
        ch=getchar();
        int num = 0;
        bool vis = 0;
        while (ch >= '0' && ch <= '9') {
            num = num * 10 - '0' + ch;
            //num = num << 3 + num << 1 + ch ^ 48;
            ch = getchar();
            vis = 1;
        }
        if (vis) a[cnt++] = num;
    } while (ch != '\n');
    for (int i = 0; i < cnt; ++i) printf("%d ", a[i]);
    return 0;
}

如果考虑大数的话,用字符串/字符数组来做即可。

#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
int main() {
    char ch;
    vector<string> ans;
    do {
        ch = getchar();
        string tmp = "";
        while (ch >= '0' && ch <= '9') {
            tmp += ch;
            ch = getchar();
        }
        if (tmp != "") ans.push_back(tmp);
    } while (ch != '\n');
        for (auto x : ans) cout << x << endl;
    return 0;
}

其他数之积

给你一个数组A[0..n-1],请你在O(n)的时间里构造一个新的数组B[0..n-1],使得:
图片说明
不能使用除法运算。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
//two pointers
int main() {
    int a[N], b[N], l[N], r[N];
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) cin >> a[i];
    l[0] = a[0], r[n - 1] = a[n - 1];
    for (int i = 1; i < n; ++i) l[i] = l[i - 1] * a[i];
    for (int i = n - 2; i >= 0; --i) r[i] = r[i + 1] * a[i];
    b[0] = r[1], b[n - 1] = l[n - 2];
    for (int i = 1; i < n - 1; ++i) b[i] = l[i - 1] * r[i + 1];
    for (int i = 0; i < n; ++i) cout << b[i] << ' ';
    return 0;
}

KMP算法

#include <iostream>
#include <string>
using namespace std;
const int N = 255;
void GetNextval(string p, int next[]) {//递归实现优化
    int pLen = p.length();
    next[0] = -1;
    int j = -1;
    int i = 0;
    while (i < pLen - 1) {
        if (j == -1 || p[i] == p[j]) {
            ++i,++j;
            if (p[i] != p[j])
                next[i] = j;
            else
                next[i] = next[j];
        } else
            j = next[j];
    }
}
void GetNext(string p, int next[]) {//递归实现
    int pLen = p.length();
    next[0] = -1;
    int j = -1;
    int i = 0;
    while (i < pLen - 1) {
        if (j == -1 || p[i] == p[j])
            next[++i] = ++j;
        else
            j = next[j];
    }
}
void Getnext(string T, int next[]) {//循环实现
    int n = T.size();
    next[0] = -1;
    next[1] = 0;
    for (int i = 1; i < n - 1;) {
        int t = i;
        while (i < n - 1 && T[i] == T[i - t]) next[++i] = i - t;
        if (i == t) next[++i] = 0;
    }
}
int KMP(string a, string b, int next[]) {
    int i = 0, j = 0, lena = a.length(), lenb = b.length();
    while (i < lena && j < lenb) {
        if (j == -1 || a[i] == b[j])
            ++i, ++j;
        else
            j = next[j];
    }
    if (j == lenb)
        return i - j;
    else
        return -1;
}
int main() {
    string a = "ababaaaba";
    string b = "ababaaaba";
    int next[N];
    for (int i = 0; i < b.length(); i++) printf("%3c", b[i]);
    cout << endl;
    Getnext(b, next);
    for (int i = 0; i < b.length(); i++) printf("%3d", next[i]);
    cout << endl;
    GetNext(b, next);
    for (int i = 0; i < b.length(); i++) printf("%3d", next[i]);
    cout << endl;
    return 0;
}

图片说明
优化后的输出结果

 -1 -1  1  0  0 -1 -1  1  3  0
 -1 -1 -1 -1 -1 -1 -1
 -1  0 -1  1  0 -1  3 -1

课本式KMP的结果

//严蔚敏原版
#include <iostream>
#include <string>
using namespace std;
const int N = 255;
void GetNextval(string p, int next[]) {
    int i=1,j=0;
    next[1]=0;
    while(i<p.length()) {
        if(j==0||p[i]==p[j])next[++i]=++j;
        else j=next[j];
    }
}
int main() {
    string a = "bbdcfbbdac";
    string b = "aaaaaaa";
    string c = "babbabab";
    int next[N];
    cout << endl;
    GetNextval(a, next);
    for (int i = 1; i < a.length(); i++) printf("%3d", next[i]);
    cout << endl;
    GetNextval(b, next);
    for (int i = 1; i < b.length(); i++) printf("%3d", next[i]);
    cout << endl;
    GetNextval(c, next);
    for (int i = 1; i < c.length(); i++) printf("%3d", next[i]);
    cout << endl;
    return 0;
}
运行结果:
  0  1  1  1  1  2  2  3  1
  0  1  2  3  4  5
  0  1  1  1  2  3  2
//严蔚敏改进
#include <iostream>
#include <string>
using namespace std;
const int N = 255;
void GetNextval(string p, int next[]) {
    int i=1,j=0;
    next[1]=0;
    while(i<p.length()) {
        if(j==0||p[i]==p[j]){
            ++i,++j;
            if(p[i]!=p[j]) next[i]=j;
            else next[i]=next[j];
        }
        else j=next[j];
    }
}
int main() {
    string a = "bbdcfbbdac";
    string b = "aaaaaaa";
    string c = "babbabab";
    int next[N];
    cout << endl;
    GetNextval(a, next);
    for (int i = 1; i < a.length(); i++) printf("%3d", next[i]);
    cout << endl;
    GetNextval(b, next);
    for (int i = 1; i < b.length(); i++) printf("%3d", next[i]);
    cout << endl;
    GetNextval(c, next);
    for (int i = 1; i < c.length(); i++) printf("%3d", next[i]);
    cout << endl;
    return 0;
}
运行结果:
  0  1  1  1  0  2  1  3  1
  0  0  0  0  0  0
  0  1  1  0  1  3  1

这是因为超级老的老教材,清华大学出版社《数据结构》第二版默认字符串第一个字符存数组长度,所以next数组的首下标也是从0开始……
其实很多东西本身并不复杂,而是有些“学者”在传播的时候把它弄复杂了。
推荐这一篇博客,我们都是跟着这个学的。
https://blog.csdn.net/v_july_v/article/details/7041827#
timu
应要求写一下这个。
按照优化后的KMP算法生成P串next数组为 -1 -1 1

ababbaabaa
aa
  aa
    a
     aab

括号/层号表示构建树

复古了一下,用了次c语言。

#include <stdio.h>
const int maxn = 3;
const int maxsize = 20;
typedef char datatype;

typedef struct treenode {
    datatype data;
    int child[maxn];
} treenode;

typedef struct levelnode {
    datatype data;
    int level;
} levelnode;


void leveltotree(int length, levelnode ltree[], int *root, treenode tree[]) {
    for (int i = 0; i < length; ++i)
        for (int j = 0; j < maxn; ++j) tree[i].child[j] = -1;
    *root = 0;
    tree[0].data = ltree[0].data;
    //初始化
    for (int i = 1, j = i - 1, tmp = j; i < length; ++i) {
        tree[i].data = ltree[i].data;  //本个节点
        if (ltree[i].level > ltree[i - 1].level) {
            tmp = j;
            j = i - 1;
            for (int k = 0; tree[j].child[k] != -1; ++k)
                tree[j].child[k] = i;  //将自己连接到双亲节点上
        } else if (ltree[i].level > ltree[j].level) {  //纳入孩子
            tree[j].child[0] = i;
        } else {
            j = tmp;
            for (int k = 0; tree[j].child[k] != -1; ++k)
                tree[j].child[k] = i;  //将自己连接到双亲节点上
        }
    }

二叉树的遍历和构建

#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char TreeElemType;
typedef struct BinTreeNode {
    TreeElemType Data;
    struct BinTreeNode *Lchild, *Rchild;
} BinTreeNode, *BinTree;
void CreatBinTree(BinTree *T) {
    // input as PreOrderTraversal
    // eg. AB#D##C##
    TreeElemType ch;
    scanf("%c", &ch);
    if (ch == '#')
        *T = NULL;
    else {
        *T = (BinTree)malloc(sizeof(BinTreeNode));
        if (!*T) exit(-1);
        (*T)->Data = ch;
        CreatBinTree(&(*T)->Lchild);
        CreatBinTree(&(*T)->Rchild);
    }
}
void PreOrderTraverse(BinTree T) {
    if (T == NULL) return;
    printf("%c", T->Data);
    PreOrderTraverse(T->Lchild);
    PreOrderTraverse(T->Rchild);
}
// To construct a binary tree through post-order traversal,
// the sequence needs to be read from back to front.
// Root --->  RChild ---> LChild
void InOrderTraverse(BinTree T) {
    if (T == NULL) return;
    InOrderTraverse(T->Lchild);
    printf("%c", T->Data);
    InOrderTraverse(T->Rchild);
}
void PostOrderTraverse(BinTree T) {
    if (T == NULL) return;
    PostOrderTraverse(T->Lchild);
    PostOrderTraverse(T->Rchild);
    printf("%c", T->Data);
}

穿线二叉树

图片说明

上图是一个常规的二叉树结构。它有很多指针指向了NULL。我们可以利用这些空的指针,来更快地实现先序/中序/后序的访问。

具体怎么做呢?其实很简单,就是让每一个有空指针的节点,左指针指向前驱,右指针指向后继。

图片说明

https://www.icourse163.org/learn/XIYOU-1002578005?tid=1450293453#/learn/content?type=detail&id=1214536856

前序+中序推树

(不带虚空节点)

HDU1710

#include <stdio.h>
const int N = 1010;
int pre[N], in[N], post[N];
int k;
struct node {
    int value;
    node *l, *r;
    node(int value = 0, node *l = NULL, node *r = NULL)
        : value(value), l(l), r(r) {}
};
void buildtree(int l, int r, int &t, node *&root) {
    int flag = -1;
    for (int i = l; i <= r; ++i)
        if (in[i] == pre[t]) {
            flag = i;
            break;
        }
    if (flag == -1) return;
    root = new node(pre[t++]);
    if (flag > l) buildtree(l, flag - 1, t, root->l);
    if (flag < r) buildtree(flag + 1, r, t, root->r);
}
void preorder(node *root) {
    if (root != NULL) {
        pre[k++] = root->value;
        preorder(root->l);
        preorder(root->r);
    }
}
void inorder(node *root) {
    if (root != NULL) {
        inorder(root->l);
        post[k++] = root->value;
        inorder(root->r);
    }
}
void postorder(node *root) {
    if (root != NULL) {
        postorder(root->l);
        postorder(root->r);
        post[k++] = root->value;
    }
}
void removetree(node *root) {
    if (root == NULL) return;
    removetree(root->l);
    removetree(root->r);
    delete root;
}
int main() {
    int n;
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) scanf("%d", &pre[i]);
        for (int i = 1; i <= n; ++i) scanf("%d", &in[i]);
        node *root;
        int t = 1;
        buildtree(1, n, t, root);
        k = 0;
        postorder(root);
        for (int i = 0; i < k; ++i)
            printf("%d%c", post[i], i == k - 1 ? '\n' : ' ');
        removetree(root);
    }
    return 0;
}

后序+中序

/*test data
9
7 4 2 8 9 5 6 3 1
4 7 2 1 8 5 9 3 6
1 2 4 7 3 5 8 9 6
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1010;
int pre[N], in[N], post[N];
int k;
struct node {
    int value;
    node *l, *r;
    node(int value = 0, node *l = NULL, node *r = NULL)
        : value(value), l(l), r(r) {}
};
void buildtree(int l, int r, int &t, node *&root) {
    int flag = -1;
    for (int i = l; i <= r; ++i)
        if (in[i] == post[t]) {
            flag = i;
            break;
        }
    if (flag == -1) return;
    root = new node(post[t--]);
    if (flag < r) buildtree(flag + 1, r, t, root->r);
    if (flag > l) buildtree(l, flag - 1, t, root->l);
}
void preorder(node *root) {
    if (root != NULL) {
        pre[k++] = root->value;
        preorder(root->l);
        preorder(root->r);
    }
}
void inorder(node *root) {
    if (root != NULL) {
        inorder(root->l);
        post[k++] = root->value;
        inorder(root->r);
    }
}
void postorder(node *root) {
    if (root != NULL) {
        postorder(root->l);
        postorder(root->r);
        post[k++] = root->value;
    }
}
void removetree(node *root) {
    if (root == NULL) return;
    removetree(root->l);
    removetree(root->r);
    delete root;
}
int main() {
    int n;
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) scanf("%d", &post[i]);
        for (int i = 1; i <= n; ++i) scanf("%d", &in[i]);
        node *root;
        int t = n;
        buildtree(1, n, t, root);
        k = 0;
        preorder(root);
        for (int i = 0; i < k; ++i)
            printf("%d%c", pre[i], i == k - 1 ? '\n' : ' ');
        removetree(root);
    }
    return 0;
}

小学奥数 填数字

1到9,填成两个三位数之和等于另一个三位数。

数量级太小,全排列查一遍就行了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
const ll mod = 1e9 + 7;
int main() {
    vector<int> a;
    for (int i = 1; i < 10; ++i) a.push_back(i);
    vector<vector<int>> ans;
    do {
        ans.push_back(a);
    } while (next_permutation(a.begin(), a.end()));
    for (vector<vector<int>>::iterator it = ans.begin(); it != ans.end(); ++it) {
        vector<int>::iterator iter = (*it).begin();
        int a = iter[0] * 100 + iter[1] * 10 + iter[2];
        int b = iter[3] * 100 + iter[4] * 10 + iter[5];
        int c = iter[6] * 100 + iter[7] * 10 + iter[8];
        if (a + b == c) {
            for (int i = 0; i < 9; ++i) cout << iter[i] << " ";
            cout << endl;
        }
    }
    return 0;
}

其实也不用存,只是熟悉一下迭代器写法。

vector<int> a;
for (int i = 1; i < 10; ++i) a.push_back(i);
do {
    if (a[0] * 100 + a[1] * 10 + a[2] + a[3] * 100 + a[4] * 10 + a[5] == a[6] * 100 + a[7] * 10 + a[8])
        for (int i = 0; i < 9; ++i) printf("%d%c", a[i], i == 8 ? '\n' : ' ');
} while (next_permutation(a.begin(), a.end()));