面试经典150题

验证回文串

如果将所有大写字符转换为小写字符,并移除所有非字母数字后,正着读和反着读一样,就认为短语是一个回文串。

cpp 复制代码
class Solution {
public:
    bool isPalindrome(string s) {
        int left = 0;
        int right = s.size()-1;
        while(left < right){
            while(left < right && !isalnum(s[left])){
                left++;
            }
            while(left < right && !isalnum(s[right])){
                right--;
            }
            if(left < right && tolower(s[left]) != tolower(s[right])){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
};

判断子序列

给定字符串s和t,判断s是否为t的子序列。

子序列是指原始字符串删除一些字符而不改变剩余字符相对位置形成的新字符串。

双指针

初始化两个指针i和j,分别指向s和t的初始位置。

每次贪心匹配,匹配成功则i和j同时右移,匹配s的下一个位置,匹配失败则j右移,i不变。

最终i移动到s的末尾,说明s是t的子序列。

cpp 复制代码
class Solution {
public:
    bool isSubsequence(string s, string t) {
        int n = s.size();
        int m = t.size();
        int sIndex = 0, tIndex = 0;
        while(sIndex < n && tIndex < m){
            if(s[sIndex] == t[tIndex]){
                sIndex++;
                tIndex++;
            }else{
                tIndex++;
            }
        }
        return sIndex == n;
    }
};

两数之和

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left = 0;
        int right = numbers.size()-1;
        while(left < right){
            int num = numbers[left] + numbers[right];
            if(num == target){
                return {left+1, right+1};
            }else if(num < target){
                left++;
            }else{
                right--;
            }
        }
        return {0,0};
    }
};

赎金信

没有前后大小顺序关系,用双指针一般。

cpp 复制代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        sort(ransomNote.begin(), ransomNote.end());
        sort(magazine.begin(), magazine.end());
        int i = 0, j = 0, m = ransomNote.size(), n = magazine.size();
        while(i<m && j<n){
            if(ransomNote[i] == magazine[j]){
                i++;
                j++;
            }else{
                j++;
            }
        }
        return i == m;
    }
};

哈希表

cpp 复制代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<int, int> count;
        for(char c : magazine){
            count[c]++;
        }
        for(char c : ransomNote){
            if(count[c] == 0){
                return false;
            }else{
                count[c]--;
            }
        }
        return true;
    }
};

数组

cpp 复制代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int count[26] = {};
        for(char c : magazine){
            count[c-'a']++;
        }
        for(char c : ransomNote){
            if(count[c-'a'] == 0){
                return false;
            }else{
                count[c-'a']--;
            }
        }
        return true;
    }
};

同构字符串

给两个字符串s和t,判断它们是否同构。

cpp 复制代码
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        unordered_map<char, char> s2t;
        unordered_map<char, char> t2s;
        
        for(int i=0; i<s.size(); i++){
            char x = s[i];
            char y = t[i];
            if((s2t.count(x) && s2t[x] != y) || (t2s.count(y) && t2s[y] != x)){
                return false;
            }
            s2t[x] = y;
            t2s[y] = x;
        }
        return true;
    }
};

分割字符串

cpp 复制代码
vector<string> splitString(string& str){
	istringstream iss(str);
	vector<string> res;
	string word;
	while(iss >> word){
		res.push_back(word);
	}
	return res;
}
cpp 复制代码
class Solution {
public:
    vector<string> splitString(string s){
        istringstream iss(s);
        vector<string> res;
        string word;
        while(iss >> word){
            res.push_back(word);
        }
        return res;
    }
    bool wordPattern(string pattern, string s) {
        unordered_map<char, string> char2s;
        unordered_map<string, char> s2char;
        
        vector<string> words = splitString(s);
        if(pattern.size() != words.size()){
            return false;
        }
        for(int i=0; i<pattern.size(); i++){
            char c = pattern[i];
            string word = words[i];
            if((char2s.count(c) && char2s[c] != word) || (s2char.count(word) && s2char[word] != c)){
                return false;
            }
            char2s[c] = word;
            s2char[word] = c;
        }
        return true;
    }
};

有效的括号

cpp 复制代码
class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;
        for(int i = 0; i<s.size(); i++){
            char ch = s[i];
            if(ch == '(' || ch == '[' || ch == '{'){
                stk.push(ch);
            }else{
                if(stk.empty()){
                    return false;
                }
                char topCh = stk.top();
                if((topCh =='[' && ch == ']') || (topCh =='(' && ch == ')') || (topCh =='{' && ch == '}')){
                    stk.pop();
                }else{
                    return false;
                }
            }
        }
        return stk.empty();
    }
};
cpp 复制代码
class Solution {
public:
    bool isValid(string s) {
        int n = s.size();
        if(n % 2 == 1){
            return false;
        }

        unordered_map<char, char> pairs = {
            {']','['},
            {'}','{'},
            {')','('}
        };

        stack<char> stk;
        for(char ch:s){
            if(pairs.count(ch)){
                if(stk.empty() || stk.top() != pairs[ch]){
                    return false;
                }
                stk.pop();
            }else{
                stk.push(ch);
            }
        }
        return stk.empty();
    }
};

简化路径

我们首先将给定的字符串path根据/分割成一个由若干字符串构成的列表,记为names。

names中包含的字符串只能为以下几种:

  • 空字符串。例如当出现多个连续的/,就会分割出空字符串。
  • 一个点.
  • 两个点...
  • 目录名。

对于空字符串以及一个点,无需处理。

对于两个点或者目录名,需要用一个栈来维护路径中的每一个目录名。当遇到两个点时,只要栈不为空,就切换到上一级(弹出栈顶目录),当遇到目录名时,就放入栈。

cpp 复制代码
class Solution {
public:
    vector<string> splitString(string &path){
        vector<string> res;
        string temp;
        for(char c : path){
            if(c == '/'){
                res.push_back(temp);
                temp.clear();
            }else{
                temp += c;
            }
        }
        res.push_back(temp);
        return res;
    }

    string simplifyPath(string path) {
        vector<string> names = splitString(path);
        vector<string> stk;
        for(int i=0; i<names.size(); i++){
            if(names[i] == ".."){
                if(!stk.empty()){
                    stk.pop_back();
                }
            }else if(!names[i].empty() && names[i] != "."){
                stk.push_back(names[i]);
            }
        }

        string res;
        if(stk.empty()){
            res = "/";
        }else{
            for(int i=0; i<stk.size(); i++){
                res += "/" + stk[i];
            }
        }
        return res;
    }
};

最小栈

设计一个支持push,pop,top操作,并能在常数时间内检索到最小元素的栈。

辅助栈

  • 入栈时,元素先入普通栈,取当前辅助栈的栈顶与元素比较,再将最小值插入栈顶。
  • 出栈时,两个一起弹出。
cpp 复制代码
class MinStack {
    stack<int> stk;
    stack<int> min_stk;
public:
    MinStack() {
        min_stk.push(INT_MAX);    
    }
    
    void push(int val) {
        stk.push(val);
        min_stk.push(min(min_stk.top(), val));
    }
    
    void pop() {
        stk.pop();
        min_stk.pop();
    }
    
    int top() {
        return stk.top();
    }
    
    int getMin() {
        return min_stk.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

逆波兰表达式求值

cpp 复制代码
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        for(int i=0; i<tokens.size(); i++){
            if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/"){
                int num2 = stk.top();
                stk.pop();
                int num1 = stk.top();
                stk.pop();
                if(tokens[i] == "+"){
                    stk.push(num1 + num2);
                }else if(tokens[i] == "-"){
                    stk.push(num1 - num2);
                }else if(tokens[i] == "*"){
                    stk.push(num1 * num2);
                }else{
                    stk.push(num1 / num2);
                }
            }else{
                stk.push(stoi(tokens[i]));
            }
        }
        return stk.top();
    }
};

基本计算器

给一个字符串表达式s,请实现一个基本计算器来计算并返回它的值。

括号展开+栈

由于字符串除了数字与括号外,只有加号和减号两种运算符。

因此,如果展开表达式中所有的括号,则得到的新表达式中,数字本身不会发生变化,只是每个数字前面的符号会变化。

需要维护一个栈ops,其中栈顶元素记录了当前位置所处的每个括号的符号。

1+2+(3-(4+5)):

  • 扫描到1+2时,由于当前位置没有被任何括号所包含,则栈顶元素为初始值+1;
  • 扫描到1+2+(3时,当前位置被一个括号包含,该括号前面的符号为+号,因此栈顶元素+1
cpp 复制代码
class Solution {
public:
    int calculate(string s) {
        stack<int> ops;
        ops.push(1);
        int sign = 1;

        int ret = 0;
        int i = 0;
        int n = s.size();
        while(i < n){
            if(s[i] == ' '){
                i++;
            }else if(s[i] == '+'){
                sign = ops.top();
                i++;
            }else if(s[i] == '-'){
                sign = -ops.top();
                i++;
            }else if(s[i] == '('){
                ops.push(sign);
                i++;
            }else if(s[i] == ')'){
                ops.pop();
                i++;
            }else{
                long num = 0;
                while(i < n && s[i] >= '0' && s[i] <= '9'){
                    num = num * 10 + s[i]-'0';
                    i++;
                }
                ret += sign * num;
            }
        }
        return ret;
    }
};
相关推荐
慢慢慢时光1 小时前
系统设计面试题
面试·系统设计
望天hous2 小时前
C# 中读取byte[]转化成数字
开发语言·javascript·c#
软件测试媛2 小时前
自动化测试面试题
开发语言·软件测试·面试·职场和发展
自动化测试薰儿2 小时前
软测面试二十问(最新面试)
软件测试·面试·职场和发展·软件测试面试
Wacanda2 小时前
C#——Json数据存储
c#·json
小万哥丶3 小时前
Kotlin 布尔值教程:深入理解与应用示例
linux·程序人生·面试·程序员·开源·kotlin·移动开发·软件工程·编程语言·技术·andriod
是五月吖3 小时前
【C#】事件学习
开发语言·学习·c#
柒拾柒_L4 小时前
PHP面向对象
开发语言·leetcode·面试·php
EricWang13584 小时前
[Kimi笔记]C# 项目涉及到几个关键概念:解决方案(Solution)、项目(Project)、代码、依赖和库。
c#
爱米的前端小笔记4 小时前
前端面试:项目细节重难点问题分享(十四)
前端·经验分享·面试·职场和发展·求职招聘