leetcode刷题笔记(3)
主题:字符串
(1)3. 无重复字符的最长子串
我的思路:用一个HashMap存储当前搜索的,还没有重复的子串(字符,索引),当出现重复值,从已put的重复值的下一个位置开始重新搜索。
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() < 2){
return s.length();
}
HashMap<String,Integer> hashMap = new HashMap<String,Integer>();
int res = 1;
int left = 0;
int temp = 0;
while(left < s.length()){
if(hashMap.get(s.substring(left,left+1)) == null){
hashMap.put(s.substring(left,left+1), left);
left++;
temp++;
}else{
left = hashMap.get(s.substring(left,left+1)) + 1;
hashMap.clear();
if(temp > res){
res = temp;
}
temp = 0;
}
}
if(temp > res){
res = temp;
}
return res;
}
}
题解:用HashSet存储字符,添加成功则说明有重复字符
class Solution {
public int lengthOfLongestSubstring(String s) {
// 哈希集合,记录每个字符是否出现过
Set<Character> occ = new HashSet<Character>();
int n = s.length();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.remove(s.charAt(i - 1));
}
while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
// 不断地移动右指针
occ.add(s.charAt(rk + 1));
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = Math.max(ans, rk - i + 1);
}
return ans;
}
}
(2)6. Z 字形变换
我的思路:每个顶角之间的gap是2n-2,从顶角向前后出发±当前行数,即为要输出的字符,注意超出最后一个顶角的字符。
class Solution {
public String convert(String s, int numRows) {
int len = s.length();
if(len <= 2 || numRows <= 1 || len <= numRows){
return s;
}
int gap = 2*numRows - 2;
String res = "";
for(int i = 0; i < numRows; i++){
for(int j = 0; j < len + gap; j += gap){
if(j - i >= 0 && j-i < len){
res += s.substring(j-i,j-i+1);
}
if(j + i < s.length() && i != 0 && i != numRows-1){
res += s.substring(j+i,j+i+1);
}
}
}
return res;
}
}
题解其他思路:按行排序;使用min(numRows,len(s))个列表来表示所有,从左至右迭代,将每个字符添加到合适的行;
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1) return s;
List<StringBuilder> rows = new ArrayList<>();
for (int i = 0; i < Math.min(numRows, s.length()); i++)
rows.add(new StringBuilder());
int curRow = 0;
boolean goingDown = false;
for (char c : s.toCharArray()) {
rows.get(curRow).append(c);
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
curRow += goingDown ? 1 : -1;
}
StringBuilder ret = new StringBuilder();
for (StringBuilder row : rows) ret.append(row);
return ret.toString();
}
}
(3)8. 字符串转换整数 (atoi)(错1)
题解思路:自动机;
class Solution {
public int myAtoi(String str) {
Automaton automaton = new Automaton();
int length = str.length();
for (int i = 0; i < length; ++i) {
automaton.get(str.charAt(i));
}
return (int) (automaton.sign * automaton.ans);
}
}
class Automaton {
public int sign = 1;
public long ans = 0;
private String state = "start";
private Map<String, String[]> table = new HashMap<String, String[]>() {{
put("start", new String[]{"start", "signed", "in_number", "end"});
put("signed", new String[]{"end", "end", "in_number", "end"});
put("in_number", new String[]{"end", "end", "in_number", "end"});
put("end", new String[]{"end", "end", "end", "end"});
}};
public void get(char c) {
state = table.get(state)[get_col(c)];
if ("in_number".equals(state)) {
ans = ans * 10 + c - '0';
ans = sign == 1 ? Math.min(ans, (long) Integer.MAX_VALUE) : Math.min(ans, -(long) Integer.MIN_VALUE);
} else if ("signed".equals(state)) {
sign = c == '+' ? 1 : -1;
}
}
private int get_col(char c) {
if (c == ' ') {
return 0;
}
if (c == '+' || c == '-') {
return 1;
}
if (Character.isDigit(c)) {
return 2;
}
return 3;
}
}
(4)10. 正则表达式匹配
(5)12. 整数转罗马数字
思路:枚举
class Solution {
public String intToRoman(int num) {
String res = "";
int temp = 0;
temp = num / 1000;
num = num - temp * 1000;
while(temp > 0){
res += "M";
temp--;
}
temp = num / 100;
num = num - temp * 100;
if(temp == 9){
res += "CM";
}else if(temp == 4){
res += "CD";
}else if(temp >= 5){
res += "D";
temp -= 5;
while(temp > 0){
res += "C";
temp--;
}
}else{
while(temp > 0){
res += "C";
temp--;
}
}
temp = num / 10;
num = num - temp * 10;
if(temp == 9){
res += "XC";
}else if(temp == 4){
res += "XL";
}else if(temp >= 5){
res += "L";
temp -= 5;
while(temp > 0){
res += "X";
temp--;
}
}else{
while(temp > 0){
res += "X";
temp--;
}
}
temp = num;
if(temp == 9){
res += "IX";
}else if(temp == 4){
res += "IV";
}else if(temp >= 5){
res += "V";
temp -= 5;
while(temp > 0){
res += "I";
temp--;
}
}else{
while(temp > 0){
res += "I";
temp--;
}
}
return res;
}
}
题解思路一:贪心模拟;将所有可能字符从大到小排列,添加比num小的中最大的,知道num==0;
题解思路二:按个十百千位分别枚举所有可能,一一匹配;
(6)13. 罗马数字转整数
我的思路:将所有的转换可能添加到hashmap中,先匹配两位的字符,没有匹配到则匹配一位的字符。
class Solution {
public int romanToInt(String s) {
int res = 0;
HashMap<String,Integer> map = new HashMap<String,Integer>();
map.put("I",1);
map.put("V",5);
map.put("X",10);
map.put("L",50);
map.put("C",100);
map.put("D",500);
map.put("M",1000);
map.put("IV",4);
map.put("IX",9);
map.put("XL",40);
map.put("XC",90);
map.put("CD",400);
map.put("CM",900);
int i = 0;
while(i < s.length()){
if(i < s.length()-1 && map.get(s.substring(i,i+2)) != null){
res += map.get(s.substring(i,i+2));
i += 2;
}else{
res += map.get(s.substring(i,i+1));
i++;
}
}
return res;
}
}
(7)14. 最长公共前缀
暴力遍历
class Solution {
public String longestCommonPrefix(String[] strs) {
String res = "";
int left = 0;
int right = 0;
for(int i = 0; i < strs[0].length(); i++){
for(String s: strs){
if(i >= s.length() || strs[0].charAt(i) != s.charAt(i)){
return res;
}
}
res += strs[0].substring(i,i+1);
}
return res;
}
}
(8)17. 电话号码的字母组合
我的思路:回溯算法
class Solution {
public List<String> letterCombinations(String digits) {
HashMap<String, String[]> map = new HashMap<String, String[]>();
map.put("1",new String[]{""});
map.put("2",new String[]{"a","b","c"});
map.put("3",new String[]{"d","e","f"});
map.put("4",new String[]{"g","h","i"});
map.put("5",new String[]{"j","k","l"});
map.put("6",new String[]{"m","n","o"});
map.put("7",new String[]{"p","q","r","s"});
map.put("8",new String[]{"t","u","v"});
map.put("9",new String[]{"w","x","y","z"});
ArrayList<String> res = new ArrayList<String>();
String temp = "";
drawBack(digits,0,res,map,temp);
return res;
}
public static void drawBack(String digits, int index, ArrayList<String> res, HashMap<String, String[]> map,String temp){
if(digits.length() > index){
String[] list = map.get(digits.substring(index,index+1));
for(String i: list){
if(index == digits.length()-1){
res.add(temp+i);
}else{
drawBack(digits,index+1,res,map,temp+i);
}
}
}
}
}
(9)20. 有效的括号
我的思路:用栈存储未匹配的字符,当前字符,如与栈顶的字符配对成功,消失,进入下一次循环。最后栈中,还有为匹配的字符说明没有
class Solution {
public boolean isValid(String s) {
Stack stack = new Stack();
char temp;
for(char c : s.toCharArray()){
if(stack.empty()){
stack.push(c);
}else{
temp = (char)stack.pop();
if(temp == '(' && c == ')'){
continue;
}else if(temp == '[' && c == ']'){
continue;
}else if(temp == '{' && c == '}'){
continue;
}else{
stack.push(temp);
stack.push(c);
}
}
}
return stack.empty();
}
}
优化:长度为单数,必不有效;
(10)22. 括号生成
我的思路:回溯算法
class Solution {
public List<String> generateParenthesis(int n) {
ArrayList<String> res = new ArrayList<String>();
String temp = "";
drawBack(n,n,res,temp);
return res;
}
public static void drawBack(int left, int right, ArrayList<String> res, String temp){
if(left > 0 && right > 0){
drawBack(left-1,right,res,temp+"(");
if(left < right){
drawBack(left,right-1,res,temp+")");
}
}else if(left == 0 && right > 0){
drawBack(left,right-1,res,temp+")");
}else{
res.add(temp);
}
}
}