LeetCode-Easy1.2:罗马数字转整数、最长公共前缀、有效括号
罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 字符
数值 I=1,V=5,X=10,L=50,C=100,D=500,M=1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X +
II 。 27 写做 XXVII, 即为 XX + V + II 。通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5
的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。 X 可以放在 L (50) 和 C (100) 的左边,来表示
40 和 90。 C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1: 输入: "III" 输出: 3 示例 2: 输入: "IV" 输出: 4 示例 3: 输入: "IX" 输出: 9 示例 4: 输入: "LVIII" 输出: 58 解释: L = 50, V= 5, III = 3. 示例 5: 输入: "MCMXCIV" 输出: 1994 解释: M = 1000, CM = 900, XC = 90, IV = 4.
大体分析一下,除了题干给出的那六种情况以外,都是可以根据字母顺序直接映射成对应数值相加。然而,在遇到小数在前,大数在后(IV),则不能直接根据字母顺序映射数值相加,因此此题的难点在于如何处理小数在前,大数在后。
解法:整体对待or区别对待
不管是哪种解法,程序都需要识别这种“小数在前,大数在后”的特殊情况。整体对待不过就是将两个字符直接映射为规定的特殊值。
说的再简单明了一点,就是在I, V, X, L,C,D 和 M基础之上,再增加IV,IX,XL,XC,CD,CM六种,字母-数值映射。只不过这个字母数值映射要求字母是两位,而不是一位。
class Solution { public: int romanToInt(string s) { map<string, int> m = {{"I", 1}, {"IV", 4}, {"IX", 9}, {"V", 5}, {"X", 10}, {"XL", 40}, {"XC", 90}, {"L", 50}, {"C", 100}, {"CD", 400}, {"CM", 900}, {"D", 500}, {"M", 1000}}; int sum = 0; for(int i=0; i<s.size();){ if(m[s.substr(i,1)]<m[s.substr(i+1,1)]){ sum+=m[s.substr(i,2)]; i+=2; } else{ sum+=m[s.substr(i,1)]; ++i; } } return sum; } };
其实这种解决方法并不可取。首先是哈希表是按照map<string,int>进行映射的,这就要求在处理string的每个元素时,还要在做一次char->string,或者直接取子串,因此性能非常 emmmmmm…
所以有了下面这种解法,避免取子串操作,但是不使用哈希表的劣势也异常明显…
class Solution { public: int romanToInt(string s) { int sum = 0; for (int i = 0;i<s.size();++i){ switch(s[i]){ case 'I': if(s[i+1]=='V'){ sum+=4; ++i; }else if(s[i+1]=='X'){ sum+=9; ++i; }else{ sum+=1; } break; case 'V': sum+=5; break; case 'X': if(s[i+1]=='L'){ sum+=40; ++i; }else if(s[i+1]=='C'){ sum+=90; ++i; }else{ sum+=10; } break; case 'L': sum+=50; break; case 'C': if(s[i+1]=='D'){ sum+=400; ++i; }else if(s[i+1]=='M'){ sum+=900; ++i; }else{ sum+=100; } break; case 'D': sum+=500; break; case 'M': sum+=1000; break; } } return sum; } };
结果就是需要用大量switch-case来区别情况,虽然时间复杂度很低,但情况也需要逐一点明。
然而,区别对待的算法思路比较新颖,在识别出六种特殊情况之一以后,对前一个数作减法。例如IV,前一个1视为-1即可。这样在按照字母顺序处理便没有任何问题。
class Solution { public: int romanToInt(string s) { map<char,int>mp={{'I', 1},{'V', 5}, {'X', 10},{'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000}}; int sum = 0; for(int i=0;i<s.size();++i){ if(mp[s[i]]<mp[s[i+1]]){ sum-=mp[s[i]]; }else{ sum+=mp[s[i]]; } } return sum; } }
经过这么一番比较,使用哈希表的优势越来越明显。
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
说明:所有输入只包含小写字母 a-z
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
取公共前缀比较常用的方法是水平扫描法,所以此题不存在难度上的争议…
解决:水平扫描法
class Solution { public: string longestCommonPrefix(vector<string>& strs) { if(strs.size()==0) return ""; string a = strs[0]; string b = ""; int flag = 0; for(int i = 0;i<a.size()&&flag==0;++i){ for(int j = 1;j<strs.size()&&flag==0;++j){ if(a[i]!=strs[j][i]||i>strs[j].size()) flag=1; } if(flag==1) break; b+=a[i]; } return b; } };
取字符串数组的首字符串作为标准,其他字符串与其比较。逐位开始,拿首字符串第i位与其他串的第i位进行比较。如果所有字符串对应位通过,则加入字符串b。
有效括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。
示例 1: 输入: "()" 输出: true 示例 2: 输入: "()[]{}" 输出: true 示例 3: 输入: "(]" 输出: false 示例 4: 输入: "([)]" 输出: false 示例 5: 输入: "{[]}" 输出: true
如果有同学之前学栈的时候有学习过四则运算法的相关程序,那么这个题确实没有难度了,拿栈来处理这种优美的对称比较问题再合适不过。
解决:Stack+HashTable
先分析一下问题,由于括号是成对出现的,而且满足一定对称关系。,当输入一个反括号的时候,就必须有对之对应的左括号。
所以,我们考虑,在遍历的时候,一旦遇到左括号就入栈;反之,一旦遇到右括号,就判断是否栈顶元素匹配,如果二者不匹配,说明错误,如果二者匹配,则弹栈。这就是“栈”在这个题目中的作用。
关于匹配,还需要多说两句,先举个例子,如果遇到了’]’,那么就要弹出栈顶元素,可是你还要再判断一下栈顶是不是’[’。然而这只是一种情况,实际上,有三种不同的括号,也就是说你需要先判断是哪种括号以后,在判断匹配问题。显然,这种if-else或者switch-case的思维定式让许多同学走了弯路。
其实,我们设计程序之前,已经知道匹配关系是怎样了,完全可以做HashTable的映射:先通过HashTable找到这种匹配关系,在判断栈顶元素是否满足这种匹配关系即可。
class Solution { public: bool isValid(string s) { map<char,char> mp={{')','('},{'}','{'},{']','['}}; if (s.size()==0) return true; if (s.size()==1) return false; stack<char> stk; for(int i=0;i<s.size();++i){ if(s[i]=='('||s[i]=='{'||s[i]=='[') stk.push(s[i]); else{ if(stk.empty()||stk.top()!=mp[s[i]]) return false; stk.pop(); } } if(stk.empty()) return true; else return false; } };
HashTable为我们提供了许许多多的便利,不单单是搜索难度降低,更是这种键值对的形式非常有利于我们实现任何想要的一对一映射。
- 点赞
- 收藏
- 分享
- 文章举报
- leetcode第三天 9回文数、13罗马数字转整数、14最长公共前缀
- 2019年5月31日 第四天练习(13罗马数字转整数)+2019年6月3日 第五天练习(14最长公共前缀)
- leetcode-Easy(JAVA)13. 罗马数字转整数
- LeetCode 13 罗马数字转整数(字符串)
- 【LeetCode】[14] 最长公共前缀
- LeetCode 14. Longest Common Prefix(最长公共前缀)
- LeetCode 14. Longest Common Prefix--字符串数组元素的最长公共前缀
- LeetCode——13 罗马数字转整数
- LeetCode刷题笔记——13. 罗马数字转整数
- leetcode 32. Longest Valid Parentheses 最长有效括号长度
- [LeetCode] Longest Valid Parentheses 最长有效括号
- [LeetCode] 12. Integer to Roman 整数转为罗马数字
- 力扣(LeetCode 13)罗马数字转整数 python
- 【LeetCode-面试算法经典-Java实现】【032-Longest Valid Parentheses(最长有效括号)】
- 【LeetCode13】罗马数字转整数
- LeetCode-14-Longest Common Prefix(最长公共前缀)
- [算法Rust,Go,Python,JS实现)]LeetCode之13-罗马数字转整数
- leetcode--最长公共前缀--python
- Leetcode-最长公共前缀
- LeetCode--13. 罗马数字转整数(Roman to Integer)