【LeetCode easy專題】leetcode 20 Valid Parentheses(附c++ string介紹以及基於範圍的for迴圈簡介)
阿新 • • 發佈:2018-12-18
題目描述如下:(文末有string型別的介紹)
本題是迴文類題目中比較簡答的一種,輸入的字串也只有“(”、“)”、“["、”]“、”{“、”}“六種,題目可以產生一些變形,如判斷括號沒有閉合等,該類題目是面試中常考的題目,解決的方法通常採用stack(棧)這種資料結構,stack是一種先進後出的結構,即first in last out,不熟悉棧的同學可以參考維基百科中棧的介紹,此處是地址 https://zh.wikipedia.org/wiki/%E5%A0%86%E6%A0%88
該題目的解答思路如下:(leetcode中的提示給出的思路很好,請大家參考。看完提示後,再看下面的思路效果更佳)
思路示例圖如下:
- 遍歷string,出現”(“、”{“、”[“ 則入棧,因為這些符號可能和其後面的符號成對匹配
- 遍歷的過程中,如果遇到了”)“、”}“、”]" ,那麼不能入棧,此時應該和棧頂的元素進行比較,如果成對匹配,那麼彈棧
- 按照上面的兩步一直進行下去,如果程式結束都棧中沒有多餘的元素,那麼該string都是成對匹配的,返回true,否則返回false
一開始寫的c++程式碼如下:
class Solution1 { public: bool isValid(string s) { auto len = s.length(); if(len % 2) return false; if(len == 0) return true; stack<char> st; st.push(s[0]); int i = 0; for(i = 1; i < len; i++) { if(s[i] == '(' || s[i] == '[' || s[i] == '{' ) { st.push(s[i]); } else { //cout << st.top() << " " << s[i] << endl; if(!st.empty() && isMatch(st.top(),s[i])) st.pop(); } } if(st.empty()) return true; else return false; } private: bool isMatch(char s1, char s2) { if(s1 == '(' && s2 == ')') return true; else if(s1 == '[' && s2 == ']') return true; else if(s1 == '{' && s2 == '}') return true; else return false; } };
程式碼雖然可以跑通,但是不夠簡明。在彈棧的時候一定要注意,此時棧不能為空,因此要提前進行判斷。
一種更優化的c++程式碼寫法如下:
//optime solution1 class Solution2{ public : bool isValid(string s) { if(s.length() == 0) return true; stack<char> st; for(int i = 0; i < s.length(); i++) { if(s[i] == '(' or s[i] == '[' or s[i] == '{') { st.push(s[i]); } else if (s[i] == ')') { if(st.empty() or st.top()!='(') return false; else st.pop(); } else if (s[i] == ']') { if(st.empty() or st.top()!='[') return false; else st.pop(); } else if (s[i] == '}') { if(st.empty() or st.top()!='{') return false; else st.pop(); } } if(st.empty()) return true; else return false; } };
優化後的程式碼較之前要簡明扼要,書寫的時候不容易出錯。在利用qt進行變異的時候,以上的程式碼還是有很多warning的,主要原因是stack和string中的有一些資料型別是不一樣的,經常出現int到unsigned long等的強制型別轉換。
一種更好的方法是直接利用string進行操作,而不是建立專門的棧。因為c++標準模板庫中,string可以有stack.pop()等這樣的功能。程式碼實現如下:
class Solution {
public:
bool isValid(string s) {
if(s.empty()) return true;
string o = "";
for (auto c : s){
if (c == '(' || c == '{' or c == '['){
o.push_back(c);
}
else if(c == ')'){
if(o.empty() || o.back() !='(') return false;
else o.pop_back();
}
else if(c == ']'){
if(o.empty() || o.back() !='[') return false;
else o.pop_back();
}
else if(c == '}'){
if(o.empty() || o.back() !='{') return false;
else o.pop_back();
}
}
return o.empty();
}
};
c++11以後,對for迴圈也進行了簡化的操作。
上面是對“基於範圍的for迴圈”的介紹,一段比較有代表性的程式碼是
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (const int& i : v) // 以 const 引用訪問
std::cout << i << ' ';
std::cout << '\n';
for (auto i : v) // 以值訪問, i 的型別是 int
std::cout << i << ' ';
std::cout << '\n';
for (auto& i : v) // 以引用訪問, i 的型別是 int&
std::cout << i << ' ';
std::cout << '\n';
for (int n : {0, 1, 2, 3, 4, 5}) // 初始化器可以是花括號初始化列表
std::cout << n << ' ';
std::cout << '\n';
int a[] = {0, 1, 2, 3, 4, 5};
for (int n : a) // 初始化器可以是陣列
std::cout << n << ' ';
std::cout << '\n';
for (int n : a)
std::cout << 1 << ' '; // 迴圈變數不必使用
std::cout << '\n';
}
c++ 11 讓c++變得更加簡單,在以後程式碼的書寫中,要儘量多使用模板庫,以及c++最新的功能。