1. 程式人生 > >【LeetCode easy專題】leetcode 20 Valid Parentheses(附c++ string介紹以及基於範圍的for迴圈簡介)

【LeetCode easy專題】leetcode 20 Valid Parentheses(附c++ string介紹以及基於範圍的for迴圈簡介)

題目描述如下:(文末有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++最新的功能。