26. 查找兄弟單詞
題目描述 :
思路分析:
這一題我是服氣的,一個是我自己的debug能力服氣,一個是對華爲OJ服氣。真的職能用這兩個詞來形容。debug 一定要在vs裏面自己編一遍,然後重新再找問題,其次就是可以利用cout<<”位置” 這樣寫法來判斷哪個支路到底走沒走、最後一個就是統計數目的時候一定要記得刷新的位置。
華爲OJ的判斷我也是服氣的,怎麼做都是不對,莫名其妙的冒出一個小尾巴是什麼鬼?
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
int find_num;
while(cin>>n){
vector<string>str;
string temp;
string explor_str;
for(int i=0;i<n;i++)
{
cin>>temp;
str.push_back(temp);
}
cin>>explor_str;
cin>>find_num;
int counter=0;
string bro_str;
for(int i=0;i<str.size();i++){
if(str[i]!=explor_str)
{
vector<int>stander(26,0);
vector<int>explor(26,0);
for(int j=0;j<str[i].length();j++){
stander[str[i][j]-'a']++;
}
for(int k=0;k<explor_str.length();k++){
explor[explor_str[k]-'a']++;
}
if(stander==explor)
{
counter++;
if(counter==find_num)
{ bro_str=str[i];
}
}
}
}
cout<<counter<<endl;
for(int i=0;i<bro_str.size();i++)
cout<<bro_str[i];
}
return 0;
}
27. 素數伴侶
題目描述 :
若兩個正整數的和爲素數,則這兩個正整數稱之爲“素數伴侶”,如2和5、6和13,它們能應用於通信加密。現在密碼學會請你設計一個程序,從已有的N(N爲偶數)個正整數中挑選出若干對組成“素數伴侶”,挑選方案多種多樣,例如有4個正整數:2,5,6,13,如果將5和6分爲一組中只能得到一組“素數伴侶”,而將2和5、6和13編組將得到兩組“素數伴侶”,能組成“素數伴侶”最多的方案稱爲“最佳方案”,當然密碼學會希望你尋找出“最佳方案”。
輸入:
有一個正偶數N(N≤100),表示待挑選的自然數的個數。後面給出具體的數字,範圍爲[2,30000]。
輸出:
輸出一個整數K,表示你求得的“最佳方案”組成“素數伴侶”的對數。
思路分析:
這一題採用的是一般圖的最大匹配算法,可以採用最大流或者匈牙利算法進行解決。但是通過分析可以知道這個題目裏面只要偶數和質數相加就可以得到素數,然後這個題目就可以採用二分圖的最大匹配算法進行解決。
二分圖就是,你可以把圖上的點分成2堆,每堆之內的點不會有邊,2堆之間,纔可能連邊。換句話說,一條邊,必定連2個來自不同堆的點。
現在,對每條邊,一定連一個奇數,一個偶數,點能按奇數和偶數分成兩部分,剛好就是二分圖
進行二分圖最大匹配的匈牙利算法基本思想:
首先將所有數字劃分爲奇數和偶數兩類
對左邊的點進行遍歷,尋找右邊與之匹配的點
1. 遇到右邊點沒有被匹配然後就採用貪心算法,將之匹配
2. 如果遇到右邊點已經匹配,就將右邊點的匹配點pre[x]進行重新匹配,尋找新的右邊點,然後將這個右邊點給原本的匹配點。
代碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> G[105];
bool flag[105];
int pre[105];
bool dfs(int k){
int x;
for(int i=0;i<G[k].size();i++){
x=G[k][i];
if (flag[x]) continue;
flag[x]=true;
if((pre[x]==0)||dfs(pre[x])){
pre[x]=k;
return true;
}
}
return false;
}
bool isprime[80000];
int nums[105];
int main(){
memset(isprime,1,sizeof(isprime));
isprime[0]=isprime[1]=false;
for(int i=4;i<80000;i+=2)isprime[i]=false;
for(int i=3;i*i<80000;i+=2)
if(isprime[i]){
for(int j=i*i;j<80000;j+=2*i) isprime[j]=false;
}
int n;
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%d",&nums[i]);
}
for(int i=1;i<=n;++i){
for(int j=i+1;j<=n;++j){
if(isprime[nums[i]+nums[j]]){
(nums[i]&1)?G[i].push_back(j):G[j].push_back(i);
}
}
}
memset(pre,0,sizeof(pre));
int ans=0;
for(int i=1;i<=n;i++){
memset(flag,false,sizeof(flag));
if (dfs(i)) ans++;
}
printf("%d\n",ans);
for(int i=1;i<=n;++i){
G[i].clear();
}
}
return 0;
}
28. 字符串加解密
題目描述 :
1、對輸入的字符串進行加解密,並輸出。
2加密方法爲:
當內容是英文字母時則用該英文字母的後一個字母替換,同時字母變換大小寫,如字母a時則替換爲B;字母Z時則替換爲a;
當內容是數字時則把該數字加1,如0替換1,1替換2,9替換0;
其他字符不做變化。
3、解密方法爲加密的逆過程。
接口描述:
實現接口,每個接口實現1個基本操作:
void Encrypt (char aucPassword[], char aucResult[]):在該函數中實現字符串加密並輸出
說明:
1、字符串以\0結尾。
2、字符串最長100個字符。
int unEncrypt (char result[], char password[]):在該函數中實現字符串解密並輸出
說明:
1、字符串以\0結尾。
2、字符串最長100個字符。
思路分析:
這一題常規思路吧,就是開始的時候我忘了加密和解密,然後導致了只能解決一個問題,後來把問題看清,問題解決了。但是後來又出現了問題,就是細節沒把握好,一直沒有debug出問題在哪兒。最終還是慢慢發現了問題的所在。要細緻啊。
想試試查表法
代碼:
#include<iostream>
#include<iomanip>
#include<string>
#include<vector>
using namespace std;
void Encrypt(string str){
int len = str.size();
for(int i=0;i<len;i++){
if((str[i]-'a')>=0 && (str[i]-'a')<25){
str[i]=str[i]-('a'-'A')+1;
}else if((str[i]-'A')>=0 && (str[i]-'A')<25){
str[i]=('a'-'A')+str[i]+1;
}else if((str[i]-'0')>=0 && (str[i]-'0')<9){
str[i]=str[i]+1;
}else if(str[i]-'a'==25)
{
str[i]='A';
}else if(str[i]-'A'==25){
str[i]='a';
}else if(str[i]=='9'){
str[i]='0';
}
}
cout<<str<<endl;
}
int unEncrypt(string str){
for(int i=0;i<str.length();i++){
if((str[i]-'a')>0 && (str[i]-'a')<=25){
str[i]=str[i]-('a'-'A')-1;
}else if((str[i]-'A')>0 && (str[i]-'A')<=25){
str[i]=('a'-'A')+str[i]-1;
}else if((str[i]-'0')>0 && (str[i]-'0')<=9){
str[i]=str[i]-1;
}else if(str[i]-'a'==0)
{
str[i]='Z';
}else if(str[i]-'A'==0){
str[i]='z';
}else if(str[i]=='0'){
str[i]='9';
}
}
cout<<str<<endl;
return 0;
}
int main(){
string str1;
string str2;
while(getline(cin,str1))
{
getline(cin,str2);
Encrypt(str1);
unEncrypt(str2);
}
return 0;
}
29. 字符串合併處理
題目描述 :
按照指定規則對輸入的字符串進行處理。
詳細描述:
將輸入的兩個字符串合併。
對合並後的字符串進行排序,要求爲:下標爲奇數的字符和下標爲偶數的字符分別從小到大排序。這裏的下標意思是字符在字符串中的位置。
對排序後的字符串進行操作,如果字符爲‘0’——‘9’或者‘A’——‘F’或者‘a’——‘f’,則對他們所代表的16進制的數進行BIT倒序的操作,並轉換爲相應的大寫字符。如字符爲‘4’,爲0100b,則翻轉後爲0010b,也就是2。轉換後的字符爲‘2’; 如字符爲‘7’,爲0111b,則翻轉後爲1110b,也就是e。轉換後的字符爲大寫‘E’。
舉例:輸入str1爲”dec”,str2爲”fab”,合併爲“decfab”,分別對“dca”和“efb”進行排序,排序後爲“abcedf”,轉換後爲“5D37BF”
接口設計及說明:
/*
功能:字符串處理
輸入:兩個字符串,需要異常處理
輸出:合併處理後的字符串,具體要求參考文檔
返回:無
*/
void ProcessString(char* str1,char str2,char strOutput)
{
}
思路分析:
這一題直接看的解析做的,讓我沒有想到的是string的處理可以這麼的多樣。
首先可以直接相加減,然後可以直接進行排序sort(s.begin(),s.end()),然後可以直接進行清空,最後尋找字符串中字符的位置用find()函數,找不到返回-1。
最後總之查表大法好。
代碼:
#include<bits/stdc++.h>
using namespace std;
const string helper1="0123456789abcdefABCDEF";
const string helper2="084C2A6E195D3B7F5D3B7F";
int main(){
string str1;
string str2;
while(cin>>str1>>str2){
string s,s1,s2;
s=str1+str2;
int len=s.size();
for(int i=0;i<s.size();i++){
if(i%2==0)
{
s1+=s[i];
}else{
s2+=s[i];
}
}
sort(s1.begin(),s1.end());
sort(s2.begin(),s2.end());
s.clear();
for(int i=0, j=0,k=0;i<len;i++){
if(i%2==0){
s+=s1[j++];
}else{
s+=s2[k++];
}
}
for(int i=0;i<len;i++){
if(helper1.find(s[i])!=-1)
s[i]=helper2[helper1.find(s[i])];
}
cout<<s<<endl;
}
return 0;
}
30. 單詞倒排
題目描述 :
對字符串中的所有單詞進行倒排。
說明:
1、每個單詞是以26個大寫或小寫英文字母構成;
2、非構成單詞的字符均視爲單詞間隔符;
3、要求倒排後的單詞間隔符以一個空格表示;如果原字符串中相鄰單詞間有多個間隔符時,倒排轉換後也只允許出現一個空格間隔符;
4、每個單詞最長20個字母;
思路分析:
這一題出現一個比較致命的錯誤,就是循環輸入沒有全部存入string裏面,然後一個比較致命的是沒有看清題意,而是直接認爲只要是空格就可以。其中isalpha()函數起到非常重要的作用
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
vector<string>res;
string temp;
for(int i=0;i<str.length();i++){
if(isalpha(str[i])){
temp+=str[i];
}else{
if(!temp.empty()){
res.push_back(temp);
temp.clear();
}
}
}
if(!temp.empty()){
res.push_back(temp);
}
for(int i=res.size()-1;i>=0;i--){
cout<<res[i];
if(i!=0){
cout<<' ';
}
}
cout<<endl;
}
return 0;
}
31. 字符串運用-密碼截取
題目描述 :
Catcher是MCA國的情報員,他工作時發現敵國會用一些對稱的密碼進行通信,比如像這些ABBA,ABA,A,123321,但是他們有時會在開始或結束時加入一些無關的字符以防止別國破解。比如進行下列變化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因爲截獲的串太長了,而且存在多種可能的情況(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量實在是太大了,他只能向電腦高手求助,你能幫Catcher找出最長的有效密碼串嗎?
思路分析:
這題本質上就是求字符串最長迴文子串。比較好用的就是
代碼:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int Manacher(string oriStr) {
string newStr;
int len = oriStr.size();
for (int i = 0; i < len; i++) {//插入間隔符
newStr += '#';
newStr += oriStr[i];
}
newStr += '#';
len = 2 * len + 1; //新串長度,必爲奇數
int maxRight = 0; //當前訪問到的所有迴文子串中,所能觸及的最右一個字符的位置
int pos = 0; //maxRight對應的迴文子串對稱軸的位置
int*RL = new int[len]; //RL[i]記錄以i爲對稱軸的最長迴文子串半徑長度(對稱軸到最左或最右的距離)
int maxLength = 0; //記錄最長迴文子串長度
for (int i = 0; i < len; i++) {
if (i < maxRight) { //分兩種情況,i在maxRight左邊和右邊
RL[i] = min(RL[2 * pos - i], maxRight - i);
}
else RL[i] = 1;
while (i - RL[i]>=0 && RL[i] + i < len && newStr[i - RL[i]] == newStr[i + RL[i]])
RL[i]++; //以i爲中心,在上步的基礎上擴展,直至到達邊界或左右字符不相等
if (maxRight < RL[i] + i - 1) {//更新maxRight和pos
maxRight = RL[i] + i - 1;
pos = i;
}
maxLength = max(maxLength, RL[i] - 1);//對以i爲中心的迴文子串在原串總的長度即爲RL[i] - 1
//證明:新串中迴文子串長度爲2*RL[i]-1,其中RL[i]個
//插入字符,則剩下的RL[i]-1個爲原字符
}
return maxLength;
}
int main() {
string str;
while (cin >> str) {
cout << Manacher(str) << endl;
}
return 0;
}
32. 整數與IP地址之間的轉換
題目描述 :
原理:ip地址的每段可以看成是一個0-255的整數,把每段拆分成一個二進制形式組合起來,然後把這個二進制數轉變成
一個長整數。
舉例:一個ip地址爲10.0.3.193
每段數字 相對應的二進制數
10 00001010
0 00000000
3 00000011
193 11000001
組合起來即爲:00001010 00000000 00000011 11000001,轉換爲10進制數就是:167773121,即該IP地址轉換後的數字就是它了。
的每段可以看成是一個0-255的整數,需要對IP地址進行校驗
思路分析:
這題讓我學到了位運算的相關知識。總之理解起來還是很饒的。不過還好,基本原理很簡單。
- IP地址: IP地址就是由四段十進制數組合得到的。每段數的範圍是0-255(也就是
(20−1)−(28−1) ),也就是IP地址每段都可以由八位二進制數表示。 - 位操作: 位操作實際上就是一個將十進制看成是二進制的操作,a<<24 表示將a(注意:是無符號數)表示的二進制數左移了24位,同理>>
- 十六進制數:十六進制用在這一題中有一個便利的地方就是 十六進制可以方便的表示爲二進制,每四位就可以表示爲一個十六進制數,比如:0xff0->1111 1111 0000 這其中我有一個低級錯誤就是忘記了0表示0000
有了這些基本概念可以很方便地寫出IP轉十進制,十進制轉IP的程序了
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
unsigned int a,b,c,d;
char ch;
while(cin>>a>>ch>>b>>ch>>c>>ch>>d){
cout<<((a<<24)|(b<<16)|(c<<8)|d)<<endl;
cin>>a;
cout<<((a& 0xff000000)>>24)<<"."<<((a& 0x00ff0000)>>16)<<"."<<((a& 0x0000ff00)>>8)<<"."<<((a& 0x000000ff))<<endl;
}
return 0;
}
33. 圖片整理
題目描述 :
Lily上課時使用字母數字圖片教小朋友們學習英語單詞,每次都需要把這些圖片按照大小(ASCII碼值從小到大)排列收好。請大家給Lily幫忙,通過C語言解決。
思路分析:
這題我只想說一句查表大法好,基本思想就是通過在建立的表中找到對應的字符,然後在統計數組裏面相應位置加1,這樣就能統計出這個位置存在有多少個相應的字符了。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
const string helper="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
while(cin>>str){
string res;
vector<int>counter(62,0);
for(int i=0;i<str.length();i++){
counter[helper.find(str[i])]++; //關鍵所在
}
for(int i=0;i<counter.size();i++){
for(int j=0;j<counter[i];j++){
res+=helper[i];
}
}
cout<<res<<endl;
}
return 0;
}
34. 蛇形矩陣
題目描述 :
題目說明
蛇形矩陣是由1開始的自然數依次排列成的一個矩陣上三角形。
樣例輸入
5
樣例輸出
1 3 6 10 15
2 5 9 14
4 8 13
7 12
11
思路分析:
這一題沒有自己做出來,是看了別人怎麼搞的,是我想多了,我想用小頂堆,結果大部分人還是在找規律。這不是我想的。
代碼:
//這一題我的想法是建一個小頂堆,然後將之輸出出來
//但是相關代碼不會,只能選擇其他的了
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
int beg=1;
for(int i=1;i<=n;i++){
cout<<beg;
int temp=beg;
for(int j=i+1;j<=n;j++){
temp+=j;
cout<<" "<<temp;
}
cout<<endl;
beg+=i;
}
}
return 0;
}
35. 字符串加密
題目描述 :
有一種技巧可以對數據進行加密,它使用一個單詞作爲它的密匙。下面是它的工作原理:首先,選擇一個單詞作爲密匙,如TRAILBLAZERS。如果單詞中包含有重複的字母,只保留第1個,其餘幾個丟棄。現在,修改過的那個單詞屬於字母表的下面,如下所示:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S C D F G H J K M N O P Q U V W X Y
上面其他用字母表中剩餘的字母填充完整。在對信息進行加密時,信息中的每個字母被固定於頂上那行,並用下面那行的對應字母一一取代原文的字母(字母字符的大小寫狀態應該保留)。因此,使用這個密匙,Attack AT DAWN(黎明時攻擊)就會被加密爲Tpptad TP ITVH。
請實現下述接口,通過指定的密匙和明文得到密文。
思路分析:
這一題有一個比較坑的地方就是沒有說明到底原文的字母是大寫還是小寫還是大寫小寫都有,所有一開始我用了大寫就錯了。然後OJ還提示我有沒有循環輸入處理多個case,我都懵逼了,while循環我明明寫了啊。把我着急了一會兒,後來改了大小寫就對了。
這個題思路上,我還是用的查表大法,先去重,然後判斷哪些是出現了一次的字符然後依次輸出,(當然我這次用了 string可以直接進行加減的概念),還有一個很重要的概念就是,如何將char類型的字符賦值給string字符串,利用:
string str="a";
str[0]=res[0];(其中res[0]是char類型的)
代碼:
#include<bits/stdc++.h>
using namespace std;
string encrypt(string str){
//去重
string res="a";
res[0]=str[0];
int flag;
for(int i=1;i<str.length();i++){
flag=0;
for(int j=0;j<res.length();j++){
if(res[j]==str[i])
flag=1;
}
if(flag==1)
{
continue;
}else{
res+=str[i];
}
}
//加上26個字母中不在key中的字母
string temp=res;
vector<int>counter(26,0);
for(int i=0;i<res.size();i++){
counter[res[i]-'a']++;
}
for(int i=0;i<26;i++){
if(counter[i]==0)
{
res+=('a'+i);
}
}
return res;
}
int main(){
string key;
string input_str;
const string helper1="abcdefghijklmnopqrstuvwxyz";
while(cin>>key){
cin>>input_str;
string helper2=encrypt(key);
string res;
for(int i=0;i<input_str.size();i++){
res+=helper2[helper1.find(input_str[i])];
}
cout<<res<<endl;
}
return 0;
}
36. 統計每個月兔子的數量
題目描述 :
有一隻兔子,從出生後第3個月起每個月都生一隻兔子,小兔子長到第三個月後每個月又生一隻兔子,假如兔子都不死,問每個月的兔子總數爲多少?
思路分析:
這一題本質上是斐波那契數列,沒什麼好講的,就是用遞歸來算,比較興奮的是第一次寫遞歸,有一些小錯誤,但是解決了,效果還不錯,一顆賽艇
代碼:
#include<bits/stdc++.h>
using namespace std;
int num_rabit(int month){
int res;
if(month==1 || month==2 )
res=1;
else
res=num_rabit(month-1)+num_rabit(month-2);
return res;
}
int main(){
int month;
while(cin>>month){
int res=num_rabit(month);
cout<<res<<endl;
}
return 0;
}
37. 求小球落地5次後的距離
題目描述 :
假設一個球從任意高度自由落下,每次落地後反跳回原高度的一半; 再落下, 求它在第5次落地時,共經歷多少米?第5次反彈多高?
思路分析:
這一題潰敗,思路上好多都是細節沒把握好。需要細緻啊。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
double len;
while(cin>>len){
double sum=len;
for(int i=1;i<5;i++)
{
len/=2.0;
sum+=len*2.0;
}
cout<<sum<<endl;
cout<<len/2<<endl;
}
return 0;
}
38. 判斷兩個IP是否屬於同一個子網
題目描述 :
子網掩碼是用來判斷任意兩臺計算機的IP地址是否屬於同一子網絡的根據。
子網掩碼與IP地址結構相同,是32位二進制數,其中網絡號部分全爲“1”和主機號部分全爲“0”。利用子網掩碼可以判斷兩臺主機是否中同一子網中。若兩臺主機的IP地址分別與它們的子網掩碼相“與”後的結果相同,則說明這兩臺主機在同一子網中。
示例:
I P 地址 192.168.0.1
子網掩碼 255.255.255.0
轉化爲二進制進行運算:
I P 地址 11010000.10101000.00000000.00000001
子網掩碼 11111111.11111111.11111111.00000000
AND運算
11000000.10101000.00000000.00000000
轉化爲十進制後爲:
192.168.0.0
I P 地址 192.168.0.254
子網掩碼 255.255.255.0
轉化爲二進制進行運算:
I P 地址 11010000.10101000.00000000.11111110
子網掩碼 11111111.11111111.11111111.00000000
AND運算
11000000.10101000.00000000.00000000
轉化爲十進制後爲:
192.168.0.0
通過以上對兩臺計算機IP地址與子網掩碼的AND運算後,我們可以看到它運算結果是一樣的。均爲192.168.0.0,所以這二臺計算機可視爲是同一子網絡。
思路分析:
這一題主要就是將字符進行劃分,之前有一道類似的題目 當時用的抖機靈的方法,其實真正用在了這道題上,並不是很實用。還是需要用遍歷的方法進行求解。其中還有一個stoi的函數十分實用。還有一個就是這一題就是判斷是否相等需要分爲255和非255,這一點非常重要。
代碼:
#include<bits/stdc++.h>
using namespace std;
vector<int>split(string s){
vector<int>res;
for(int i=0;i<s.length();i++){
string temp;
while(i<s.length() & s[i]!='.')
{
temp.push_back(s[i]);
i++;
}
res.push_back(stoi(temp));
}
return res;
}
int main(){
string mask;
string ip1;
string ip2;
while(cin>>mask>>ip1>>ip2){
vector<int>Mask=split(mask);
vector<int>ipA=split(ip1);
vector<int>ipB=split(ip2);
bool flag=true;
for(int i=0;flag && i<Mask.size();i++){
if(Mask[i]==255){
if(ipA[i]!=ipB[i]){
flag=false;
break;
}
}else{
if(ipA[i] & Mask[i] != ipB[i] & Mask[i] ){
flag=false;
break;
}
}
}
if(flag){
cout<<0<<endl;
}else{
cout<<2<<endl;
}
}
return 0;
}
39. 輸入一行字符,分別統計出包含英文字母、空格、數字和其它字符的個數。
題目描述 :
輸入一行字符,分別統計出包含英文字母、空格、數字和其它字符的個數。
思路分析:
這一題思路上沒什麼問題,主要有一個是OJ的注意點,這一題不難,但是有一個地方屎坑,就是while(cin>>str){}進行輸入會一個勁的報錯,這是這個函數的問題,因爲這類題目輸入一堆字符串難免會進行拆分的,導致統計錯誤。因此只能採用while(getline(cin,str)){}進行輸入,才正確。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
vector<int>counter(4,0);
for(int i=0;i<str.length();i++){
char cur=(char)str[i];
if((cur>='a' && cur<='z') || (cur>='A' && cur<='Z') )
counter[0]++;
else if(cur==' ')
counter[1]++;
else if(cur<='9' && cur>='0')
counter[2]++;
else
counter[3]++;
}
for(int i=0;i<counter.size();i++){
cout<<counter[i]<<endl;
}
}
return 0;
}
40. 稱砝碼
題目描述 :
現有一組砝碼,重量互不相等,分別爲m1,m2,m3…mn;
每種砝碼對應的數量爲x1,x2,x3…xn。現在要用這些砝碼去稱物體的重量,問能稱出多少中不同的重量。
思路分析:
這一題是一道DP問題,主要就是用一個weights[j]=weights[j-1]+j*m[i]的公式,還有一個很重要的就是find(vector.begin(),vector.end(),w)==vector.end()
代表了其中不存在該值,全部都遍歷過了。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;// 砝碼數
int m[10]={0}; //每個砝碼質量
int x[10]={0}; //每個砝碼數量
while(cin>>n){
for(int i=0;i<n;i++)
cin>>m[i];
for(int i=0;i<n;i++)
cin>>x[i];
vector<int>weights; //存儲的所有的砝碼質量
//將所有砝碼稱出的質量放入隊列
weights.push_back(0);
for(int i=1;i<=x[0];i++){
weights.push_back(i*m[0]);
}
for(int i=1;i<n;i++){
int len=weights.size();
for(int j=1;j<=x[i];j++){
for(int k=0;k<len;k++){
int w=weights[k]+j*m[i];
if(find(weights.begin(),weights.end(),w)==weights.end())
{
weights.push_back(w);
}
}
}
}
cout<<weights.size()<<endl;
}
return 0;
}
41. 學英語
題目描述 :
Jessi初學英語,爲了快速讀出一串數字,編寫程序將數字轉換成英文:
如22:twenty two,123:one hundred and twenty three。
說明:
數字爲正整數,長度不超過九位,不考慮小數,轉化結果爲英文小寫;
輸出格式爲twenty two;
非法數據請返回“error”;
關鍵字提示:and,billion,million,thousand,hundred。
方法原型:public static String parse(long num)
思路分析:
這一題基本都過了,最後OJ說我格式不對,不知道哪兒不對。然後一個問題就是好多地方考慮 的不夠細緻,改進了好多遍,希望下次能夠認真仔細一點。其實這一題就是寫一個函數然後主函數負責將數字劃分爲三部分就行了。思路上不是很難。
代碼:
#include<bits/stdc++.h>
using namespace std;
const string helper1[5]={"and","billion","million","thousand","hundred"};
const string helper2[8]={"twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"};
const string helper3[10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
const string helper4[10]={"ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"};
string thrible_num(long n){
string res;
vector<int>point_num;
vector<int>temp;
while (n) {
temp.push_back(n % 10);
n /= 10;
}
for (int i = 0; i < temp.size() ; i++) {
int temp1 = temp[i];
point_num.push_back(temp1);
}
int len = point_num.size();
if (len == 1) {
res += helper3[point_num[0]];
}
else if (len == 2) {
if (point_num[0] == 1)
{
res += helper4[point_num[1]];
}
else
{
res += helper2[point_num[1] - 2];
res += " ";
if(point_num[0]!=0)
res += helper3[point_num[0]];
}
}
else if (len == 3) {
res += helper3[point_num[2]];
res += " ";
if (point_num[1] == 1)
{
res += helper1[4];
res +=" ";
res+="and";
res+=" ";
res += helper4[point_num[0]];
}
else if(point_num[1] >1)
{
res += helper1[4];
res +=" ";
res+="and";
res+=" ";
res += helper2[point_num[1] - 2];
res += " ";
if(point_num[0]!=0)
res += helper3[point_num[0]];
}else if(point_num[1] == 0){
res += helper1[4];
res +=" ";
res+="and";
res+=" ";
res += helper3[point_num[0]];
}
}
return res;
}
int main(){
long int n;
while(cin>>n){
string res;
if(n<1000){
res=thrible_num(n);
}else if(n>=1000 && n<1000000){
int temp=n/1000;
n=n%1000;
string str;
res=thrible_num(temp);
str=thrible_num(n);
res+=" ";
res+="thousand";
res+=" ";
res+=str;
}else if(n>=1000000 && n<1000000000){
int temp=n/1000000;
n=n%1000000;
string str;
res=thrible_num(temp);
res+=" ";
res+="million";
res+=" ";
temp=n/1000;
str=thrible_num(temp);
res+=str;
res+=" ";
res+="thousand";
res+=" ";
n=n%1000;
str=thrible_num(n);
res+=str;
}
while (res[res.size() - 1] == ' ') res.erase(res.end() - 1);
cout<<res<<endl;
}
return 0;
}
42. 迷宮問題
題目描述 :
定義一個二維數組N*M(其中2<=N<=10;2<=M<=10),如5 × 5數組下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫着走或豎着走,不能斜着走,要求編程序找出從左上角到右下角的最短路線。入口點爲[0,0],既第一空格是可以走的路。
Input
一個N × M的二維數組,表示一個迷宮。數據保證有唯一解,不考慮有多解的情況,即迷宮只有一條通道。
思路分析:
這一題開始想的用DP,然後無情被打臉,其實這一題和之前的旅行商問題和揹包問題都是採用的回溯法,主要的思想我寫在了【算法知識總結】回溯法 這篇博客裏面了。
注意:
其中vector設置的二維矩陣在數據的存取上有一些新的知識,非常厲害
1. 二維vector矩陣push_back({i,j})
2. 二維vector矩陣遍歷輸入
for (auto &i : maze)
for (auto &j : i)
cin >> j;
.
3. 二維vector矩陣初始化
maze=vector<vector<int>>(N,vector<int>(M,0))
代碼:
#include<iostream>
#include<vector>
using namespace std;
int N, M; //分別代表行和列
vector<vector<int>> maze;//迷宮矩陣
vector<vector<int>> path_temp;//存儲當前路徑,第一維表示位置
vector<vector<int>> path_best;//存儲最佳路徑
void MazeTrack(int i, int j)
{
maze[i][j] = 1;//表示當前節點已走,不可再走
path_temp.push_back({ i, j });//將當前節點加入到路徑中
if (i == N - 1 && j == M - 1) //判斷是否到達終點
if (path_best.empty() || path_temp.size() < path_best.size())
path_best = path_temp;
if (i - 1 >= 0 && maze[i - 1][j] == 0)//探索向上走是否可行
MazeTrack(i - 1, j);
if (i + 1 < N && maze[i + 1][j] == 0)//探索向下走是否可行
MazeTrack(i + 1, j);
if (j - 1 >= 0 && maze[i][j - 1] == 0)//探索向左走是否可行
MazeTrack(i, j - 1);
if (j + 1 < M && maze[i][j + 1] == 0)//探索向右走是否可行
MazeTrack(i, j + 1);
maze[i][j] = 0; //恢復現場,設爲未走
path_temp.pop_back();
}
int main()
{
while (cin >> N >> M)
{
maze = vector<vector<int>>(N, vector<int>(M, 0));
path_temp.clear();
path_best.clear();
for (auto &i : maze)
for (auto &j : i)
cin >> j;
MazeTrack(0, 0);//回溯尋找迷宮最短通路
for (auto i : path_best)
cout << '(' << i[0] << ',' << i[1] << ')' << endl;//輸出通路
}
return 0;
}
43 . sudoku
題目描述 :
問題描述:數獨(Sudoku)是一款大衆喜愛的數字邏輯遊戲。玩家需要根據9X9盤面上的已知數字,推算出所有剩餘空格的數字,並且滿足每一行、每一列、每一個粗線宮內的數字均含1-9,並且不重複。
輸入:
包含已知數字的9X9盤面數組[空缺位以數字0表示]
輸出:
完整的9X9盤面數組
思路分析:
這一題看的別人的寫法採用的是DFS深度優先搜索。
代碼:
#include <iostream>
using namespace std;
bool sign = false;
int num[9][9];
void Output()
{
for (int i = 0; i < 9; i++){
for (int j = 0; j < 8; j++)
cout << num[i][j] << " ";
cout << num[i][8];
cout << endl;
}
}
/* 判斷key填入n格時是否滿足條件,n代表第幾個格子 */
bool Check(int n, int key)
{
/* 判斷n所在橫列是否合法 */
for (int i = 0; i < 9; i++){
/* j爲n豎座標 */
int j = n / 9;
if (num[j][i] == key)
return false;
}
/* 判斷n所在豎列是否合法 */
for (int i = 0; i < 9; i++){
/* j爲n橫座標 */
int j = n % 9;
if (num[i][j] == key)
return false;
}
int y = n / 9 / 3 * 3;
int x = n % 9 / 3 * 3;
/* 判斷n所在的小九宮格是否合法 */
for (int i = y; i < y + 3; i++)
for (int j = x; j < x + 3; j++)
if (num[i][j] == key)
return false;
return true;
}
/* 深搜 */
int DFS(int n)
{
/* 所有的都符合,退出搜索,n代表格子數,共81個格子,0~80 */
if (n > 80){
sign = true;
return 0;
}
if (num[n / 9][n % 9] != 0)
DFS(n + 1);
else{
/* 否則對當前位一次填入1~9進行測試 */
for (int i = 1; i <= 9; i++){
if (Check(n, i)){
num[n / 9][n % 9] = i;
/* 繼續搜索,後續位也填1~9測試,直到最後一位,通過的話置true */
DFS(n + 1);
/* 返回時如果構造成功,則直接退出 */
if (sign)
return 0;
/* 如果構造不成功,還原當前位 */
num[n/9][n%9] = 0;
}
}
}
return 0;
}
int main()
{
for (int i = 0; i < 9; i++){
for (int j = 0; j < 9; j++)
cin >> num[i][j];
}
DFS(0); //從第0格開始填
Output();
}
44 . 名字的漂亮度
題目描述 :
給出一個名字,該名字有26個字符串組成,定義這個字符串的“漂亮度”是其所有字母“漂亮度”的總和。
每個字母都有一個“漂亮度”,範圍在1到26之間。沒有任何兩個字母擁有相同的“漂亮度”。字母忽略大小寫。
給出多個名字,計算每個名字最大可能的“漂亮度”。
思路分析:
這一題本質上是一個字符數字的統計以及排序的問題。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
while(n--){
string temp;
int k=26;
int res=0;
cin>>temp;
vector<int>counter(26,0);
for(int j=0;j<temp.length();j++){
if(temp[j]>='a' && temp[j]<='z' )
counter[temp[j]-'a']++;
else
counter[temp[j]-'A']++;
}
sort(counter.begin(),counter.end());
for(int i=counter.size()-1;i>=0;i--){
res+=counter[i]*(k--);
}
cout<<res<<endl;
}
}
return 0;
}
45 . 按字節截取字符串
題目描述 :
編寫一個截取字符串的函數,輸入爲一個字符串和字節數,輸出爲按字節截取的字符串。但是要保證漢字不被截半個,如”我ABC”4,應該截爲”我AB”,輸入”我ABC漢DEF”6,應該輸出爲”我ABC”而不是”我ABC+漢的半個”。
思路分析:
這一題開始沒多想,就是直接一個如果存在字母常規的添加到輸出字符串裏面,如果存在漢字就多進一個。後來看了別人的看法,感覺也挺有的價值的。但是按照上面的做法沒有考察到任何知識點,所以先無視string的這個功能。
漢字佔兩個字節,每個字節的ASCII碼最高位均爲1,由於char默認爲帶符號類型,所以漢字的ASCII碼小於0,而英文數字等其他字符佔一個字節,ASCII碼最高位爲0,值在0~127之間。因此,只需要判斷該字節是否小於0就能推斷出是否爲半個漢字。再向前推算有連續幾個半個漢字,若有偶數個,則輸出最後半個漢字,否則不輸出。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
int n;
while(cin>>str){
cin>>n;
string res;
for(int i=0;i<n;i++){
if(str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z' )
{
res+=str[i];
}else{
i++;
res+=str[i];
}
}
cout<<res<<endl;
}
return 0;
}
46 . 線性插值
題目描述 :
信號測量的結果包括測量編號和測量值。存在信號測量結果丟棄及測量結果重複的情況。1.測量編號不連續的情況,認爲是測量結果丟棄。對應測量結果丟棄的情況,需要進行插值操作以更準確的評估信號。採用簡化的一階插值方法,由丟失的測量結果兩頭的測量值算出兩者中間的丟失值。假設第M個測量結果的測量值爲A,第N個測量結果的測量值爲B。則需要進行(N-M-1)個測量結果的插值處理。進行一階線性插值估計的第N+i個測量結果的測量值爲A+( (B-A)/(N-M) )*i (注:N的編號比M大。)
例如:只有測量編號爲4的測量結果和測量編號爲7的測量結果,測量值分別爲4和10則需要補充測量編號爲5和6的測量結果。其中測量編號爲5的測量值=4 + ((10-4)/(7-4))*1 = 6。其中測量編號爲6的測量值=4 + ((10-4)/(7-4))*2 = 8 2.測量編號相同,則認爲測量結果重複,需要對丟棄後來出現的測量結果。
思路分析:
這一題開始沒看懂 啥是捨棄 啥又是插值,其實插值是比較簡單,但是這個思路理順不太好整。其中題目給出的例子中有一個m值是沒有用的。因此還被懵逼了。然後講回正題,其中,第二行輸入的兩個值就是起初的基準值,然後將兩個值分別代表標號以及主值,然後下一個標號還是一樣的就捨棄即continue,如果不一樣就將之與之前那一行的編號對比,如果中間差幾個值,就需要進行插值。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m;
while(cin>>n>>m){
int M,N,A,B;
cin>>M>>A;
cout<<M<<" "<<A<<endl;
for(int i=1;i<n;i++){
cin>>N>>B;
if(N==M)
continue;
else
{
for(int j=1;j<N-M;j++){
cout<<M+j<<" "<<A+(B-A)/(N-M)*j<<endl;
}
cout<<N<<" "<<B<<endl;
M=N;
A=B;
}
}
}
return 0;
}
47 . 從單向鏈表中刪除指定值節點
題目描述 :
輸入一個單向鏈表和一個節點的值,從單向鏈表中刪除等於該值的節點,刪除後如果鏈表中無節點則返回空指針。
鏈表結點定義如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
詳細描述:
本題爲考察鏈表的插入和刪除知識。
鏈表的值不能重複
構造過程,例如
1 -> 2
3 -> 2
5 -> 1
4 -> 5
7 -> 2
最後的鏈表的順序爲 2 7 3 1 5 4
刪除 結點 2
則結果爲 7 3 1 5 4
思路分析:
這一題是考察基本功的,但是還是不太會,很傷。說明還需要多練習。
代碼:
#include<bits/stdc++.h>
using namespace std;
struct ListNode{
int key;
ListNode* next;
ListNode(int x):key(x),next(NULL){}
};
int main(){
int n;
int key,pre;
while(cin>>n>>key){
ListNode* head=new ListNode(key);
n--;
while(n--){
cin>>key>>pre;
ListNode* p=head;
while(p->key != pre){
p=p->next;
}
ListNode* curr=new ListNode(key);
curr->next=p->next;
p->next=curr;
}
cin>>key;
ListNode* p=head;
while(p){
if(p->key !=key )
cout<<p->key<<" ";
p=p->next;
}
cout<<endl;
}
return 0;
}
48 . 多線程
題目描述 :
問題描述:有4個線程和1個公共的字符數組。線程1的功能就是向數組輸出A,線程2的功能就是向字符輸出B,線程3的功能就是向數組輸出C,線程4的功能就是向數組輸出D。要求按順序向數組賦值ABCDABCDABCD,ABCD的個數由線程函數1的參數指定。
思路分析:
這一題是考察多線程,但是我這個投機取巧的,沒啥用,還需要多學習啊。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
string str="ABCD";
for(int i=1;i<n;i++)
{
str=str+"ABCD";
}
cout<<str<<endl;
}
return 0;
}
49 . 四則運算
題目描述 :
輸入一個string類型的字符串,裏面是一條四則運算字符串,然後得到計算結果
思路分析:
這一題採用python進行計算就是一兩行代碼的問題,但是這一題實際考察的是,遞歸下降算法的使用,其實這類題目(當然包括括號的匹配問題)都是一個堆棧問題,通過堆棧的壓棧和彈出,進行匹配計算的。
代碼:
#include<bits/stdc++.h>
using namespace std;
void addNum(deque<string>& Q,int num){
if(!Q.empty()){
int cur=0;
if(Q.back()=="*" || Q.back()=="/"){
string top=Q.back();
Q.pop_back();
stringstream ss(Q.back());
ss>>cur;
Q.pop_back();
num=top=="*"?(cur*num):(cur/num);
}
}
stringstream ss;
ss<<num;
Q.push_back(ss.str());
}
int getNum(deque<string>& Q){
int num=0,R=0;
string f("+");
while(!Q.empty()){
stringstream ss(Q.front());
ss>>num;
Q.pop_front();
R=(f=="+")?(R+num):(R-num);
if(!Q.empty()){
f=Q.front();
Q.pop_front();
}
}
return R;
}
int* value(string & s,int i){
deque<string>Q;
int pre=0;
while(i<s.length() && s[i]!=')' && s[i]!=']' && s[i]!='}'){
if(s[i]>='0' && s[i]<='9'){
pre=pre*10+s[i++]-'0';
}else if(s[i]!='(' && s[i]!='[' && s[i]!='{'){
addNum(Q,pre);
string ss;
ss+=s[i++];
Q.push_back(ss);
pre=0;
}else{
int * bra=NULL;
bra=value(s,i+1);
pre=bra[0];
i=bra[1]+1;
}
}
addNum(Q,pre);
int *R=new int[2];
R[0]=getNum(Q);
R[1]=i;
return R;
}
int main(){
string s;
while(cin>>s){
int *R=value(s,0);
cout<<R[0]<<endl;
}
return 0;
}
50 . 輸出單向鏈表中倒數第k個節點
題目描述 :
輸入說明
1 輸入鏈表結點個數
2 輸入鏈表的值
3 輸入k的值
思路分析:
這一題是一個基礎考察結果我還是不怎麼熟,感覺很沮喪。還是多練練吧 其實鏈表真的還是比較基礎的問題。而且很實用。多練習。
代碼:
#include<bits/stdc++.h>
using namespace std;
struct ListNode{
int key;
ListNode * next;
ListNode(int n):key(n),next(NULL){}
};
int main(){
int n;
while(cin>>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;
}
cin>>val;
p=head;
if(val==0){
cout<<"0"<<endl;
}else if((n-val)>=0){
for(int i=1;i<=(n-val);i++){
p=p->next;
}
cout<<p->key<<endl;
}else{
cout<<"NULL"<<endl;
}
}
return 0;
}
51 . 計算字符串的距離
題目描述 :
Levenshtein 距離,又稱編輯距離,指的是兩個字符串之間,由一個轉換成另一個所需的最少編輯操作次數。許可的編輯操作包括將一個字符替換成另一個字符,插入一個字符,刪除一個字符。編輯距離的算法是首先由俄國科學家Levenshtein提出的,故又叫Levenshtein Distance。
Ex:
字符串A:abcdefg
字符串B: abcdef
通過增加或是刪掉字符”g”的方式達到目的。這兩種方案都需要一次操作。把這個操作所需要的次數定義爲兩個字符串的距離。
要求:
給定任意兩個字符串,寫出一個算法計算它們的編輯距離。
思路分析:
這一題是一道動態規劃的題目,動態規劃一般應用在最優子串的問題上,這一道題目也是這樣。
設
設
設
1.
2.
- 若將它們修改爲相等,則對兩個字符串至少還要操作
D(i−1,j−1) 次- 若刪除
ai或在bj後添加ai,則對兩個字符串至少還要操作D(i−1,j)次 若刪除bj或在ai後添加bj,則對兩個字符串至少還要操作D(i,j−1)次
此時
顯然,
其中使用vector建立二維數組的語法:
vector<vector<int>>dp(s1.size()+1,vector<int>(s2.size()+1,0));
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
string s1,s2;
while(cin>>s1>>s2){
vector<vector<int>>dp(s1.size()+1,vector<int>(s2.size()+1,0));
for(int i=1;i<=s2.length();i++){
dp[0][i]=i;
}
for(int i=1;i<=s1.length();i++){
dp[i][0]=i;
}
for(int i=1;i<=s1.length();i++){
for(int j=1;j<=s2.length();j++){
int min1=min(dp[i-1][j],dp[i][j-1])+1;
dp[i][j]=min((s1[i-1]==s2[j-1]?0:1)+dp[i-1][j-1],min1);
}
}
cout<<dp[s1.size()][s2.size()]<<endl;
}
return 0;
}
52 . 楊輝三角的變形
題目描述 :
1
1 1 1
1 2 3 2 1
1 3 6 7 6 3 1
1 4 10 16 19 16 10 4 1
以上三角形的數陣,第一行只有一個數1,以下每行的每個數,是恰好是它上面的數,左上角數到右上角的數,3個數之和(如果不存在某個數,認爲該數就是0)。
求第n行第一個偶數出現的位置。如果沒有偶數,則輸出-1。例如輸入3,則輸出2,輸入4則輸出3。
思路分析:
這一題 數學歸納法。
代碼:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
int res=0;
if(n==1 || n==2)
{
res=0;
}else if(n%2==1){
res=2;
}else if(n%4==0){
res=3;
}else if(n%2==0 && n%4!=0){
res=4;
}
cout<<res<<endl;
}
return 0;
}
或者:
//思路:1.找規律,發現,如果用數組表示的話,第1行的1並不是在最左邊,而是在第n個元素位置(n代表行號)
// 2.第n行的元素的第一個和最後一個是要提前賦值爲1.其他行的元素,除第一個外,按照公式
// a[i][j]=a[i][j-1]+a[i][j]+a[i][j+1];
#include<iostream>
#include<vector>
using namespace std;
void printYH(int n)
{
vector<vector<int> >a(n,vector<int>(2*n-1,0));
a[0][n-1]=a[n-1][0]=a[n-1][2*n-2]=1;
if(n<2)
{
cout<<"-1"<<endl;
return ;
}
for(int i=1;i<n;++i)
for(int j=1;j<2*n-2;++j)
a[i][j]=a[i-1][j]+a[i-1][j-1]+a[i-1][j+1];
for(int i=0;i<2*n-1;++i)
if(a[n-1][i]!=0 && (a[n-1][i]%2==0))
{
cout<<i+1<<endl;
return ;
}
return ;
}
int main()
{
int n;
while(cin>>n)
{
printYH(n);
}
return 0;
}
53 . 表達式求值
題目描述 :
給定一個字符串描述的算術表達式,計算出結果值。
輸入字符串長度不超過100,合法的字符包括”+, -, *, /, (, )”,”0-9”,字符串內容的合法性及表達式語法的合法性由做題者檢查。本題目只涉及整型計算。
思路分析:
這一題 將中綴表達式轉爲後綴表達式,使用棧來進行計算。
代碼:
//1.字符串預處理,針對可能出現的“{,},[,],-”等特殊情況進行替換,判斷‘-’是負號還是減號,負號前面+0,轉變成減法運算
//2.將中綴字符串轉變爲後綴字符串數組
//3.對後綴字符串數組進行求解
#include<iostream>
#include<vector>
#include<string>
#include<stack>
#include<sstream>
using namespace std;
bool cmpPriority(char top,char cur)//比較當前字符與棧頂字符的優先級,若棧頂高,返回true
{
if((top=='+' || top=='-') && (cur=='+' || cur=='-'))
return true;
if((top=='*' || top=='/') && (cur=='+' || cur=='-'|| top=='*' || top=='/'))
return true;
if(cur==')')
return true;
return false;
}
void preProcess(string &str)//對字符串進行預處理
{
for(int i=0;i<str.size();++i)
{
if(str[i]=='{')//將‘{、}、[,]’替換成'()'
str[i]='(';
else if(str[i]=='}')
str[i]=')';
else if(str[i]=='[')
str[i]='(';
else if(str[i]==']')
str[i]=')';
else if(str[i]=='-')
{
if(i==0)//將'-'前面添加0轉變成減法運算
str.insert(0,1,'0');
else if(str[i-1]=='(')
str.insert(i,1,'0');
}
}
}
vector<string> mid2post(string &str)
{
vector<string>vstr;
stack<char>cstack;
for(int i=0;i<str.size();++i)//掃描字符串
{
string temp="";
if(str[i]>='0' && str[i]<='9')//若是數字
{
temp+=str[i];
while(i+1<str.size() && str[i+1]>='0' && str[i+1]<='9')
{
temp+=str[i+1];//若是連續數字
++i;
}
vstr.push_back(temp);
}
else if(cstack.empty() || str[i]=='(')//若棧空或者字符爲'('
cstack.push(str[i]);
else if(cmpPriority(cstack.top(),str[i]))//若棧頂元素優先級較高,棧頂元素出棧
{
if(str[i]==')')//若當前字符是右括號,棧中元素出棧,入字符串數組中,直到遇到'('
{
while(!cstack.empty() && cstack.top()!='(')
{
temp+=cstack.top();
cstack.pop();
vstr.push_back(temp);
temp="";
}
cstack.pop();
}
else//棧中優先級高的元素出棧,入字符串數組,直到優先級低於當前字符
{
while(!cstack.empty() && cmpPriority(cstack.top(),str[i]))
{
temp+=cstack.top();
cstack.pop();
vstr.push_back(temp);
temp="";
}
cstack.push(str[i]);
}
}
else//當前字符優先級高於棧頂元素,直接入棧
cstack.push(str[i]);
}
while(!cstack.empty())//棧中還存在運算符時,出棧,存入字符串數組
{
string temp="";
temp+=cstack.top();
cstack.pop();
vstr.push_back(temp);
}
return vstr;
}
int calcPostExp(vector<string> & vstr)//對後綴表達式進行求值,主要是根據運算符取出兩個操作數進行運算
{
int num,op1,op2;
stack<int>opstack;
for(int i=0;i<vstr.size();++i)
{
string temp=vstr[i];
if(temp[0]>='0' && temp[0]<='9')//如果當前字符串是數字,利用字符串流轉化爲int型
{
stringstream ss;
ss<<temp;
ss>>num;
opstack.push(num);
}
else if(vstr[i]=="+")//若是操作符,取出兩個操作數,進行運算,並將結果存入
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1+op2);
}
else if(vstr[i]=="-")
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1-op2);
}
else if(vstr[i]=="*")
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1*op2);
}
else if(vstr[i]=="/")
{
op2=opstack.top();
opstack.pop();
op1=opstack.top();
opstack.pop();
opstack.push(op1/op2);
}
}
return opstack.top();//最終的棧頂元素就是求解的結果
}
void calcExp(string str)
{
vector<string>vstr;
preProcess(str);//對字符串進行預處理
vstr=mid2post(str);//將中綴表達式轉爲後綴,保存在字符串數組中,方便下一步求解
int res=calcPostExp(vstr);
cout<<res<<endl;
}
int main()
{
string str;
while(getline(cin,str))
{
calcExp(str);
}
return 0;
}