【LeetCode easy专题】leetcode 20 Valid Parentheses(附c++ string介绍以及基于范围的for循环简介)

题目描述如下:(文末有string类型的介绍)

【LeetCode easy专题】leetcode 20 Valid Parentheses(附c++ string介绍以及基于范围的for循环简介)_第1张图片

本题是回文类题目中比较简答的一种,输入的字符串也只有“(”、“)”、“["、”]“、”{“、”}“六种,题目可以产生一些变形,如判断括号没有闭合等,该类题目是面试中常考的题目,解决的方法通常采用stack(栈)这种数据结构,stack是一种先进后出的结构,即first in last out,不熟悉栈的同学可以参考维基百科中栈的介绍,此处是地址 https://zh.wikipedia.org/wiki/%E5%A0%86%E6%A0%88

该题目的解答思路如下:(leetcode中的提示给出的思路很好,请大家参考。看完提示后,再看下面的思路效果更佳)

【LeetCode easy专题】leetcode 20 Valid Parentheses(附c++ string介绍以及基于范围的for循环简介)_第2张图片

思路示例图如下: 

  • 遍历string,出现”(“、”{“、”[“ 则入栈,因为这些符号可能和其后面的符号成对匹配
  • 遍历的过程中,如果遇到了”)“、”}“、”]" ,那么不能入栈,此时应该和栈顶的元素进行比较,如果成对匹配,那么弹栈
  • 按照上面的两步一直进行下去,如果程序结束都栈中没有多余的元素,那么该string都是成对匹配的,返回true,否则返回false
  • 【LeetCode easy专题】leetcode 20 Valid Parentheses(附c++ string介绍以及基于范围的for循环简介)_第3张图片

一开始写的c++代码如下:

class Solution1 {
public:
    bool isValid(string s) {
        auto len = s.length();
        if(len % 2)
            return false;
        if(len == 0)
            return true;
        stack 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 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();
    }
};

关于string的介绍,维基百科中的介绍详略得当,重点突出,易于立即理解 https://zh.wikipedia.org/wiki/String_(C%2B%2B%E6%A0%87%E5%87%86%E5%BA%93) 

 c++11以后,对for循环也进行了简化的操作。

https://zh.cppreference.com/w/cpp/language/range-for

上面是对“基于范围的for循环”的介绍,一段比较有代表性的代码是

#include 
#include 
 
int main() {
    std::vector 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++最新的功能。 

 

你可能感兴趣的:(leetcode)