【leetcode刷题笔记(3)】

本文介绍了LeetCode中涉及字符串处理的若干经典问题,包括求解最长无重复字符子串、Z字形变换字符串以及字符串与整数间的转换。通过不同思路的比较,展示了多种解决方案,例如使用HashMap或HashSet存储状态,回溯算法以及栈的应用。这些问题涵盖了字符串处理的基础和进阶技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主题:字符串

(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);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值