LeetCode刷题(十四)-----字符串-------medium部分(Java、C++)

22. 括号生成

给出n代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出n=3,生成结果为:

[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
思路一:c++版本,暴力构造法+剪枝
构造法生成括号
首先分析:需要构造有效的括号,数量上,左右括号分别都为n个。
其次:左括号的数量需要大于等于右括号的数量,
由两个前提可写出如下代码,从空串中逐步递归添加左右括号,
1.如果右括号比左括号多,说明无效则返回
2.如果左括号数量超过N,则与题意不符,返回
3.如果左右括号都达到了指定数量,则可以将其添加到数组中保存
4.如果以上条件都没有满足,则尝试加入新的左括号和右括号
在这里插入图片描述
递归停止的条件有三个: 1.右括号比左括号多了,终止递归 2.左括号的数量大于N了。(N是题目中给出的生成括号的数量),终止递归 3.是生成了合法的数量,此时将括号放入答案数组,并终止递归

作者:sanxiconze-2
链接:https://leetcode-cn.com/problems/generate-parentheses/solution/cban-ben-bao-li-gou-zao-fa-jian-zhi-by-sanxiconze-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路二:
首先观察
1.一对括号只有一种()
2.两对括号有2种()(), (()) # 在一对的基础上,所有的空白位置左边、中间、右边插入一对括号,去重
3.三对括号有5种"((()))", “(()())”, “(())()”, “()(())”, “()()()” # 在两对的基础上,每一组括号对的每一个位置插入一对括号,并去重
4.随意找到n对括号数的每个可插入的位置插入一个括号,去重即为n+1对括号数的解。
正确性
• 由于n-1对括号满足条件,在任意位置插入一对括号也是满足条件的;
• 也不会漏解,因为n对可解括号一定有一对括号是连续的,去掉后一定在n-1对正确括号中。
具体做法:

  1. 保留两个集合pre,now;
  2. 每次遍历pre中的每个字符串
  3. 尝试在每一个字符串的每个位置插入一对括号,并将结果加入now集合
  4. pre = now
    在这里插入图片描述
    作者:ma-xing
    链接:https://leetcode-cn.com/problems/generate-parentheses/solution/gou-zao-fa-jian-dan-cu-bao-de-si-lu-by-ma-xing/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我的:

class Solution {
public:
    void helper(int left,int right,string tmp,vector<string> &result)
    {
        if(left == 0 && right == 0)
        {
            result.push_back(tmp);
            return;
        }
        if(left > right || left <0 || right<0)
        {
            return ;
        }
        helper(left - 1,right,tmp + '(',result);
        helper(left, right - 1,tmp + ')',result);
    }
    vector<string> generateParenthesis(int n) 
    {
        vector<string>result;
        helper(n,n,"",result);
        return result;
    }
};

49.字母异位词分组

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:
输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
输出:
[
[“ate”,“eat”,“tea”],
[“nat”,“tan”],
[“bat”]
]
说明:
• 所有输入均为小写字母。
• 不考虑答案输出的顺序。
思路一:
方法一:排序数组分类
思路:当且仅当它们的排序字符串相等时,两个字符串是字母异位词。
算法:维护一个映射ans:{String -> List},其中每个键K 是一个排序字符串,每个值是初始输入的字符串列表,排序后等于K。
在 Java 中,我们将键存储为字符串,例如,code。 在 Python 中,我们将键存储为散列化元组,例如,(‘c’, ‘o’, ‘d’, ‘e’)。
在这里插入图片描述
在这里插入图片描述
复杂度分析
时间复杂度:O(NKlogK),其中N是 strs 的长度,而K是strs中字符串的最大长度。当我们遍历每个字符串时,外部循环具有的复杂度为 O(N)。然后,我们在O(KlogK)的时间内对每个字符串排序。
空间复杂度:O(NK),排序存储在 ans 中的全部信息内容。

方法二:按计数分类
思路:当且仅当它们的字符计数(每个字符的出现次数)相同时,两个字符串是字母异位词。
算法:我们可以将每个字符串s 转换为字符数count,由26个非负整数组成,表示a, b,c的数量等。我们使用这些计数作为哈希映射的基础。
在 Java 中,我们的字符数 count 的散列化表示将是一个用 字符分隔的字符串。 例如,abbccc 将表示为 #1#2#3#0#0#0 …#0,其中总共有26个条目。 在 python 中,表示将是一个计数的元组。 例如,abbccc 将表示为 (1,2,3,0,0,…,0),其中总共有 26 个条目。
在这里插入图片描述
在这里插入图片描述
复杂度分析
时间复杂度:O(NK),其中 N是 strs 的长度,而 K是 strs 中字符串的最大长度。计算每个字符串的字符串大小是线性的,我们统计每个字符串。
空间复杂度:O(NK),排序存储在 ans 中的全部信息内容。

作者:LeetCode
链接:https://leetcode-cn.com/problems/group-anagrams/solution/zi-mu-yi-wei-ci-fen-zu-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路二:
在这里插入图片描述
代码
在这里插入图片描述
链接:https://leetcode-cn.com/problems/group-anagrams/solution/cji-jian-shi-xian-fu-jie-guo-he-si-lu-by-haru-8/
思路三:
在原始信息和哈希映射使用的实际键之间建立映射关系。在这里体现为,将单词字母按字母表顺序排列,若排列结果相同,则为字母异位词
在这里插入图片描述
链接:https://leetcode-cn.com/problems/group-anagrams/solution/cxiang-xi-ti-jie-by-youlookdeliciousc-26/

我的:

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) 
    {
        unordered_map<string, vector<string>> hashmap;
        for(auto s:strs)
        {
            string temp;
            temp = s;
            sort(temp.begin(),temp.end());
            hashmap[temp].push_back(s);
        }
        int len = hashmap.size();
        vector<vector<string>> ans(len);
        int index = 0;
        for(auto i:hashmap)
        {
            ans[index] = i.second;
            ++index;
        }
        return ans;    
    }
};

17. 电话号码的字母组合

给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意1不对应任何字母。

在这里插入图片描述
示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

思路一:方法:回溯
回溯是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。

给出如下回溯函数 backtrack(combination, next_digits) ,它将一个目前已经产生的组合 combination 和接下来准备要输入的数字 next_digits 作为参数。

如果没有更多的数字需要被输入,那意味着当前的组合已经产生好了。
如果还有数字需要被输入:
遍历下一个数字所对应的所有映射的字母。
将当前的字母添加到组合最后,也就是 combination = combination + letter。
重复这个过程,输入剩下的数字:backtrack(combination+letter, next_digits[1:])。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复杂度分析
时间复杂度: O(3N×4M) ,其中 N 是输入数字中对应 3 个字母的数目(比方说 2,3,4,5,6,8),M是输入数字中对应 4 个字母的数目(比方说 7,9),N+M 是输入数字的总数。
空间复杂度:O(3^N ×4^M ),这是因为需要保存3^N ×4^M 个结果。

作者:LeetCode
链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/dian-hua-hao-ma-de-zi-mu-zu-he-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路二:
方法概述:
利用数据结构中队列的“先进先出”的知识,采用实时更新队列的内容实现遍历。
步骤说明:
1.建立一个map哈希表;
2.新建一个队列;
3.将第一个字符串所对应的码表逐步进入到队列中;
4.出队操作,存储当前出队的string;
5.将此string与后一个字符串所对应的码表中每一个值相加并逐步进入到队列中;
6.最终队列中存储的即为所有情况的string
代码描述:
在这里插入图片描述
在这里插入图片描述
作者:su-ge
链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/c-dui-lie-jian-dan-shi-xian-yi-dong-by-su-ge/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我的:

class Solution {
public:
    vector<string> letterCombinations(string digits) 
    {
        vector<string> res;
        map<char, string> m = { {'2',"abc"},{'3',"def"},{'4',"ghi"},{'5',"jkl"},{'6',"mno"},{'7',"pqrs"},{'8',"tuv"},{'9',"wxyz"} };
        int size = digits.size();
        queue<string> que;

        for(int j = 0; j < m[digits[0]].size(); j++)
        {
            string str;
            str.push_back(m[digits[0]][j]);
            que.push(str);
        }
        string s;
        for(int i = 1; i < size; i++)
        {
            int length = que.size();
            while(length--)
            {
                for(int j = 0; j < m[digits[i]].size();j++)
                {
                    s = que.front();
                    s = s + m[digits[i]][j];
                    que.push(s);
                }
                que.pop();
            }
        }
        while(!que.empty())
        {
            res.push_back(que.front());
            que.pop();
        }
        return res;    
    }
};

227. 基本计算器 II

实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式仅包含非负整数,+, - ,*,/四种运算符和空格 。整数除法仅保留整数部分。

示例 1:
输入: “3+2*2”
输出: 7
示例 2:
输入: " 3/2 "
输出: 1
示例 3:
输入: " 3+5 / 2 "
输出: 5
说明:
• 你可以假设所给定的表达式都是有效的。
• 请不要使用内置的库函数 eval。

想法一:
任何表达式最后都可以精简成 pre + cur +/-/*// next;
pre cur next 分别为三个状态
状态转移方式
sign = + : pre += cur, cur = next
sign = - : pre += cur, cur = -next
sign = * : cur *= next
sign = / : cur /= next

例如:
样例 “3+2*2”
pre = 3, cur = 2, next = 2
逐步更新状态
初始化:pre = 0, cur = 0, next = 0, sign = +
1.pre = 0, cur = 0, next = 3, sign = +
2.pre = 0, cur = 3, next = 2, sign = *
3.pre = 3, cur = 2, next = 2

一个更复杂的样例:"1000/10/5+32+1"
pre = 1000/10/5, cur = 3
2, next = 1
逐步更新状态
初始化:pre = 0, cur = 0, next = 0, sign = +
1.pre = 0, cur = 0, next = 1000, sign = /
2.pre = 0, cur = 1000, next = 10, sign = /
3.pre = 0, cur = 100, next = 5, sign = +
4.pre = 0, cur = 20, next = 3, sign = *
5.pre = 20, cur = 3, next = 2, sign = +
6.pre = 20, cur = 6, next = 1

代码实现如下:
在这里插入图片描述
在这里插入图片描述
作者:charon____
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/cjian-dan-jie-fa-yi-ci-xun-huan-chang-shu-kong-jia/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

想法二:
思路
1.按照手算思路模拟实现。
2.用一个stack nums记录操作数,用stack op记录操作符。
3.顺序遍历,按顺序读取每个char。
31. 空格再见。
32. 如果是数字,记录一下。
33. 如果是±/,就要开始计算了。原则是这样的。
只要上次的操作符是
/,那么上个操作数和当前刚拿到的第二操作数都在,直接计算这一步的结果,然后把他们出栈。
如果这一次的操作符是*/,那么不管上个操作数是+还是-,操作数和操作符都要入栈。因为优先级高。
当然如果你上个操作数是空,也要入栈。
剩下唯一一种情况,就是上个操作符是±了,计算结果入栈,新操作符也入栈。

4.因为遇到操作符才会计算,为了在循环里一同处理,在字符串后面加个操作符。
5.遍历完毕的时候,nums顶为计算结果。
答题
在这里插入图片描述
在这里插入图片描述
我的:

class Solution {
public:
    int calculate(string s) 
    {
        int pre = 0, cur = 0 ,next = 0;
        char sign = '+';
        for(char ch : s)
        {
            if(ch == ' ')
            {
                continue;
            }
            if(ch >= '0' && ch <= '9')
            {
                next = 10* next + (ch - '0');
            }
            else
            {
                process(pre,cur,next,sign);
                sign = ch;
            }
        }
        process(pre,cur,next,sign);
        return pre + cur;
    }

    void process(int& pre,int& cur,int& next,char sign)
    {
        if(sign == '+')
        {
            pre += cur;
            cur = next;
        }
        else if(sign == '-')
        {
            pre += cur;
            cur = -next;
        }
        else if(sign == '*')
        {
            cur *= next;
        }
        else
        {
            cur /= next;
        }
        next = 0;
    }
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值