当前位置: 首页 > article >正文

02数组+字符串+滑动窗口+前缀和与差分+双指针(D2_字符串(D2_刷题练习))

目录

1. 最长公共前缀

1.1. 题目描述

1.2. 解题方案

方案一:纵向对比

方案二:横向对比

方案三:最值对比

方案四:分治

方案五:二分

1.3. 知识归纳

2. 左旋转字符串(简单)

2.1. 题目描述

2.2. 解题思路

方法一:字符串切片

方法二:列表遍历拼接

方法三:字符串遍历拼接

3. 表示数值的字符串(中等)

3.1. 题目描述

3.2. 解题思路

方法一:确定有限状态自动机

4. 把字符串转换成整数(中等)

4.1. 题目描述

4.2. 解题思路

5. 交替合并字符串(简单)

5.1. 题目描述

5.2. 解题思路

方法一:双指针

6. 字符串的最大公因子(简单)

6.1. 题目描述

6.2. 解题思路

方法一:枚举

方法二:枚举优化

方法三:数学

7. 反转字符串中的元音字母(简单)

7.1. 题目描述

7.2. 解题思路

方法一:双指针

8. 递增的三元子序列(中等)

8.1. 题目描述

8.2. 解题思路

方法一:双向遍历

方法二:贪心

9. 压缩字符串(中等)

9.1. 题目描述

9.2. 解题思路

方法一:双指针

10. 反转字符串中的单词(中等)

10.1. 题目描述

10.2. 解题思路

方法一:使用语言特性

方法二:自行编写对应的函数

方法三:双端队列

11. 字符串变形(简单)

11.1. 题目描述

11.2. 解题思路

方法一:双逆转(推荐使用)

方法二:分割字符串+栈(扩展思路)

12. 最长公共前缀

12.1. 题目描述

12.2. 解题思路

方法一:遍历查找(推荐使用)

13. 验证IP地址

13.1. 题目描述

13.2. 解题思路

方法一:分割字符串比较法(推荐使用)

方法二:正则表达式(扩展思路)

14. 大数加法

14.1. 题目描述

14.2. 解题思路

方法一:模拟法(建议使用)

15. 无重复字符的最长子串

15.1. 题目描述

15.2. 解题思路

方法一:滑动窗口

16. 找到字符串中所有字母异位词(中等)

16.1. 题目描述

16.2. 解题思路

方法一:滑动窗口

方法二:优化的滑动窗口

17. 定长子串中元音的最大数目(中等)

17.1. 题目描述

17.2. 解题思路

方法一:滑动窗口

18. 判断是否为回文字符串

18.1. 题目描述

18.2. 解题思路

方法一:首尾依次比较法(推荐使用)

方法二:反转字符串比较法(扩展思路)

19. 最小覆盖子串(较难)

19.1. 题目描述

19.2. 解题思路

方法一:哈希表匹配(推荐使用)

20. 反转字符串(入门)

20.1. 题目描述

20.2. 解题思路

解法一

解法二

解法三


1. 最长公共前缀

1.1. 题目描述

1.2. 解题方案

对于一个问题,采用一题多解,才能深刻理解其考察的知识点,进行举一反三。

最长公共前缀,可横向对比 / 竖向对比 / 最值对比 / 分治 / 二分方法来完成题解。

方案一:纵向对比
    public String longestCommonPrefix(String[] strs) {
        for (int i = 0; i < strs[0].length(); i++) {
            char ch = strs[0].charAt(i);
            for (int j = 1; j < strs.length; j++) {
                if (i == strs[j].length() || strs[j].charAt(i) != ch) return strs[0].substring(0, i);
            }
        }
        return strs[0];
    }
方案二:横向对比
    // idea6:横向扫描(暴力之一)
    public String longestCommonPrefix6(String[] strs) {
        String prefix = strs[0];

        for (String s : strs) prefix = compareStr(prefix, s);

        return prefix;
    }
    private String compareStr(String s1, String s2) {
        int idx = 0;
        while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;

        return s1.substring(0, idx);
    }
方案三:最值对比
    public String longestCommonPrefix3(String[] strs) {
        String min = strs[0], max = strs[0];

        for (String str : strs) {
            // bug1:字符串的compare和integer的不一样,并非-1 / 0 / 1,而是长度相减作为返回值。
            if (min.compareTo(str) > 0) min = str;
            if (max.compareTo(str) < 0) max = str;
        }

        return compareStr(min, max);
    }
    private String compareStr(String s1, String s2) {
        int idx = 0;
        while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;

        return s1.substring(0, idx);
    }
方案四:分治
    private String partition(String[] strs, int left, int right) {
        if (left == right) return strs[left];

        int mid = left + (right - left >> 1);
        String s1 = partition(strs, left, mid);
        String s2 = partition(strs, mid + 1, right);

        return compareStr(s1, s2);
    }
    private String compareStr(String s1, String s2) {
        int idx = 0;
        while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;

        return s1.substring(0, idx);
    }
方案五:二分
    public String longestCommonPrefix5(String[] strs) {
        String s = strs[0];
        // 有可能需要idx = 0的位置,所以也会需要s.len的位置。
        int low = 0, high = s.length();
        // 用二分法去快速寻找公共前缀的右边界。
        while (low < high) {
            int mid = low + (high - low + 1 >> 1);// 为了low不越界,这里必须+1防止死循环。
            String midStr = s.substring(0, mid);

            if (isMatchAll(strs, midStr)) low = mid;
            else high = mid - 1;
        }
        return s.substring(0, low);
    }
    private boolean isMatchAll(String[] strs, String str) {
        for (String s : strs) {
            if (s.length() < str.length() || !str.equals(s.substring(0, str.length()))) return false;
        }
        return true;
    }

1.3. 知识归纳

最长公共前缀,可横向对比 / 竖向对比 / 最值对比 / 分治 / 二分方法来完成题解。

对于分治来讲,可多线程操作加快速度;

对于二分,考察对抽象二分的理解,将二分规则进行抽象。

2. 左旋转字符串(简单)

2.1. 题目描述

2.2. 解题思路

方法一:字符串切片
class Solution {
    public String reverseLeftWords(String s, int n) {
        return s.substring(n, s.length()) + s.substring(0, n);
    }
}
方法二:列表遍历拼接
class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder res = new StringBuilder();
        for(int i = n; i < s.length(); i++)
            res.append(s.charAt(i));
        for(int i = 0; i < n; i++)
            res.append(s.charAt(i));
        return res.toString();
    }
}
方法三:字符串遍历拼接
class Solution {
    public String reverseLeftWords(String s, int n) {
        String res = "";
        for(int i = n; i < s.length(); i++)
            res += s.charAt(i);
        for(int i = 0; i < n; i++)
            res += s.charAt(i);
        return res;
    }
}

3. 表示数值的字符串(中等)

3.1. 题目描述

3.2. 解题思路

方法一:确定有限状态自动机
class Solution {
    public boolean isNumber(String s) {
        Map<State, Map<CharType, State>> transfer = new HashMap<State, Map<CharType, State>>();
        Map<CharType, State> initialMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_SPACE, State.STATE_INITIAL);
            put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
            put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
            put(CharType.CHAR_SIGN, State.STATE_INT_SIGN);
        }};
        transfer.put(State.STATE_INITIAL, initialMap);
        Map<CharType, State> intSignMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
            put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
        }};
        transfer.put(State.STATE_INT_SIGN, intSignMap);
        Map<CharType, State> integerMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
            put(CharType.CHAR_EXP, State.STATE_EXP);
            put(CharType.CHAR_POINT, State.STATE_POINT);
            put(CharType.CHAR_SPACE, State.STATE_END);
        }};
        transfer.put(State.STATE_INTEGER, integerMap);
        Map<CharType, State> pointMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
            put(CharType.CHAR_EXP, State.STATE_EXP);
            put(CharType.CHAR_SPACE, State.STATE_END);
        }};
        transfer.put(State.STATE_POINT, pointMap);
        Map<CharType, State> pointWithoutIntMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
        }};
        transfer.put(State.STATE_POINT_WITHOUT_INT, pointWithoutIntMap);
        Map<CharType, State> fractionMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
            put(CharType.CHAR_EXP, State.STATE_EXP);
            put(CharType.CHAR_SPACE, State.STATE_END);
        }};
        transfer.put(State.STATE_FRACTION, fractionMap);
        Map<CharType, State> expMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
            put(CharType.CHAR_SIGN, State.STATE_EXP_SIGN);
        }};
        transfer.put(State.STATE_EXP, expMap);
        Map<CharType, State> expSignMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
        }};
        transfer.put(State.STATE_EXP_SIGN, expSignMap);
        Map<CharType, State> expNumberMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
            put(CharType.CHAR_SPACE, State.STATE_END);
        }};
        transfer.put(State.STATE_EXP_NUMBER, expNumberMap);
        Map<CharType, State> endMap = new HashMap<CharType, State>() {
  
  {
            put(CharType.CHAR_SPACE, State.STATE_END);
        }};
        transfer.put(State.STATE_END, endMap);

        int length = s.length();
        State state = State.STATE_INITIAL;

        for (int i = 0; i < length; i++) {
            CharType type = toCharType(s.charAt(i));
            if (!transfer.get(state).containsKey(type)) {
                return false;
            } else {
                state = transfer.get(state).get(type);
            }
        }
        return state == State.STATE_INTEGER || state == State.STATE_POINT || state == State.STATE_FRACTION || state == State.STATE_EXP_NUMBER || state == State.STATE_END;
    }

    public CharType toCharType(char ch) {
        if (ch >= '0' && ch <= '9') {
            return CharType.CHAR_NUMBER;
        } else if (ch == 'e' || ch == 'E') {
            return CharType.CHAR_EXP;
        } else if (ch == '.') {
            return CharType.CHAR_POINT;
        } else if (ch == '+' || ch == '-') {
            return CharType.CHAR_SIGN;
        } else if (ch == ' ') {
            return CharType.CHAR_SPACE;
        } else {
            return CharType.CHAR_ILLEGAL;
        }
    }

    enum State {
        STATE_INITIAL,
        STATE_INT_SIGN,
        STATE_INTEGER,
        STATE_POINT,
        STATE_POINT_WITHOUT_INT,
        STATE_FRACTION,
        STATE_EXP,
        STATE_EXP_SIGN,
        STATE_EXP_NUMBER,
        STATE_END
    }

    enum CharType {
        CHAR_NUMBER,
        CHAR_EXP,
        CHAR_POINT,
        CHAR_SIGN,
        CHAR_SPACE,
        CHAR_ILLEGAL
    }
}

4. 把字符串转换成整数(中等)

4.1. 题目描述

请问什么是有符号整数?

有符号整数,就是int,因为有正负之分,所以16位的第一位表示正负,0为正,1为负所以能表示的范围

是-32768~+32767(-2e15~2e15-1)而无符号整数,就是定义为unsigned int,因为第一位不用代

表正负了,没有符号,全是正的啊,所以16位全为有效位,所以范围是0~65535(0~2e16-1)

4.2. 解题思路

class Solution {

    public int strToInt(String str) {
        char[] c = str.trim().toCharArray();
        if(c.length == 0) return 0;
        int res = 0, bndry = Integer.MAX_VALUE / 10;
        int i = 1, sign = 1;
        if(c[0] == '-') sign = -1;
        else if(c[0] != '+') i = 0;
        for(int j = i; j < c.length; j++) {
            if(c[j] < '0' || c[j] > '9') break;
            if(res > bndry || res == bndry && c[j] > '7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (c[j] - '0');
        }
        return sign * res;
    }
}

若不使用trim() / strip() 方法,而从头开始遍历字符串,则可以将空间复杂度降低至 O(1) ,代码如下:

class Solution {
    public int strToInt(String str) {
        int res = 0, bndry = Integer.MAX_VALUE / 10;
        int i = 0, sign = 1, length = str.length();
        if(length == 0) return 0;
        while(str.charAt(i) == ' ')
            if(++i == length) return 0;
        if(str.charAt(i) == '-') sign = -1;
        if(str.charAt(i) == '-' || str.charAt(i) == '+') i++;
        for(int j = i; j < length; j++) {
            if(str.charAt(j) < '0' || str.charAt(j) > '9') break;
            if(res > bndry || res == bndry && str.charAt(j) > '7')
                return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (str.charAt(j) - '0');
        }
        return sign * res;
    }

}

5. 交替合并字符串(简单)

5.1. 题目描述

5.2. 解题思路

方法一:双指针

class Solution {
    public String mergeAlternately(String word1, String word2) {
        int m = word1.length(), n = word2.length();
        int i = 0, j = 0;

        StringBuilder ans = new StringBuilder();
        while (i < m || j < n) {
            if (i < m) {
                ans.append(word1.charAt(i));
                ++i;
            }
            if (j < n) {
                ans.append(word2.charAt(j));
                ++j;
            }
        }
        return ans.toString();
    }
}

6. 字符串的最大公因子(简单)

6.1. 题目描述

什么是最大公因数 最大公因数的解释

1、最大公因数,也称为最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。

2、a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最

大公约数也有同样的记号。

求最大公约数有多种方法,常见的有质因数分解法、短除法、辗转相除法、更相减损法。

与最大公约数相对应的概念是最小公倍数,a,b的最小公倍数记为[a,b]。

6.2. 解题思路

方法一:枚举

class Solution {
    // 字符串最大公因子
    public String gcdOfStrings(String str1, String str2) {
        // 获取两个字符串长度
        int len1 = str1.length(), len2 = str2.length();
        // 从长度小的开始枚举
        for (int i = Math.min(len1, len2); i >= 1; --i) {
            // 前缀串的长度必然是两个字符串长度的约数才能满足条件
            if (len1 % i == 0 && len2 % i == 0) {
                // 截取子串
                String X = str1.substring(0, i);
                // 检测子串是否能被两个字符串整除
                if (check(X, str1) && check(X, str2)) {
                    return X;
                }
            }
        }
        return "";
    }

    public boolean check(String t, String s) {
        int lenx = s.length() / t.length();
        StringBuffer ans = new StringBuffer();
        for (int i = 1; i <= lenx; ++i) {
            ans.append(t);
        }
        return ans.toString().equals(s);
    }
}

方法二:枚举优化

class Solution {
	// 字符串最大公因子
    public String gcdOfStrings(String str1, String str2) {
        // 获取两个字符串长度
        int len1 = str1.length(), len2 = str2.length();
        // 截取子串(截取到最大公因子)
        String T = str1.substring(0, gcd(len1, len2));
		// 检测子串是否能被两个字符串整除
        if (check(T, str1) && check(T, str2)) {
            return T;
        }
        return "";
    }

    public boolean check(String t, String s) {
        int lenx = s.length() / t.length();
        StringBuffer ans = new StringBuffer();
        for (int i = 1; i <= lenx; ++i) {
            ans.append(t);
        }
        return ans.toString().equals(s);
    }

    // 求最大公因子
    public int gcd(int a, int b) {
        int remainder = a % b;
        while (remainder != 0) {
            a = b;
            b = remainder;
            remainder = a % b;
        }
        return b;
    }
}

方法三:数学

class Solution {
	// 字符串最大公因子
    public String gcdOfStrings(String str1, String str2) {
        // 两个字符串相连不相等,直接返回空串
        if (!str1.concat(str2).equals(str2.concat(str1))) {
            return "";
        }
        // 
        return str1.substring(0, gcd(str1.length(), str2.length()));
    }
	// 截取子串(截取到最大公因子)
    public int gcd(int a, int b) {
        int remainder = a % b;
        while (remainder != 0) {
            a = b;
            b = remainder;
            remainder = a % b;
        }
        return b;
    }
}

7. 反转字符串中的元音字母(简单)

7.1. 题目描述

7.2. 解题思路

方法一:双指针

class Solution {
    public String reverseVowels(String s) {
        int n = s.length();
        char[] arr = s.toCharArray();
        int i = 0, j = n - 1;
        while (i < j) {
            while (i < n && !isVowel(arr[i])) {
                ++i;
            }
            while (j > 0 && !isVowel(arr[j])) {
                --j;
            }
            if (i < j) {
                swap(arr, i, j);
                ++i;
                --j;
            }
        }
        return new String(arr);
    }

    public boolean isVowel(char ch) {
        return "aeiouAEIOU".indexOf(ch) >= 0;
    }

    public void swap(char[] arr, int i, int j) {
        char temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

8. 递增的三元子序列(中等)

8.1. 题目描述

8.2. 解题思路

方法一:双向遍历

class Solution {
    public boolean increasingTriplet(int[] nums) {
        int n = nums.length;
        if (n < 3) {
            return false;
        }
        int[] leftMin = new int[n];
        leftMin[0] = nums[0];
        for (int i = 1; i < n; i++) {
            leftMin[i] = Math.min(leftMin[i - 1], nums[i]);
        }
        int[] rightMax = new int[n];
        rightMax[n - 1] = nums[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], nums[i]);
        }
        for (int i = 1; i < n - 1; i++) {
            if (nums[i] > leftMin[i - 1] && nums[i] < rightMax[i + 1]) {
                return true;
            }
        }
        return false;
    }
}

方法二:贪心

class Solution {
    public boolean increasingTriplet(int[] nums) {
        int n = nums.length;
        if (n < 3) {
            return false;
        }
        int first = nums[0], second = Integer.MAX_VALUE;
        for (int i = 1; i < n; i++) {
            int num = nums[i];
            if (num > second) {
                return true;
            } else if (num > first) {
                second = num;
            } else {
                first = num;
            }
        }
        return false;
    }
}

9. 压缩字符串(中等)

9.1. 题目描述

9.2. 解题思路

方法一:双指针

class Solution {
    public int compress(char[] chars) {
        int n = chars.length;
        int write = 0, left = 0;
        for (int read = 0; read < n; read++) {
            if (read == n - 1 || chars[read] != chars[read + 1]) {
                chars[write++] = chars[read];
                int num = read - left + 1;
                if (num > 1) {
                    int anchor = write;
                    while (num > 0) {
                        chars[write++] = (char) (num % 10 + '0');
                        num /= 10;
                    }
                    reverse(chars, anchor, write - 1);
                }
                left = read + 1;
            }
        }
        return write;
    }

    public void reverse(char[] chars, int left, int right) {
        while (left < right) {
            char temp = chars[left];
            chars[left] = chars[right];
            chars[right] = temp;
            left++;
            right--;
        }
    }
}

10. 反转字符串中的单词(中等)

10.1. 题目描述

10.2. 解题思路

方法一:使用语言特性

class Solution {
    public String reverseWords(String s) {
        // 除去开头和末尾的空白字符
        s = s.trim();
        // 正则匹配连续的空白字符作为分隔符分割
        List<String> wordList = Arrays.asList(s.split("\\s+"));
        Collections.reverse(wordList);
        return String.join(" ", wordList);
    }
}

方法二:自行编写对应的函数

class Solution {
    public String reverseWords(String s) {
        StringBuilder sb = trimSpaces(s);

        // 翻转字符串
        reverse(sb, 0, sb.length() - 1);

        // 翻转每个单词
        reverseEachWord(sb);

        return sb.toString();
    }

    public StringBuilder trimSpaces(String s) {
        int left = 0, right = s.length() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s.charAt(left) == ' ') {
            ++left;
        }

        // 去掉字符串末尾的空白字符
        while (left <= right && s.charAt(right) == ' ') {
            --right;
        }

        // 将字符串间多余的空白字符去除
        StringBuilder sb = new StringBuilder();
        while (left <= right) {
            char c = s.charAt(left);

            if (c != ' ') {
                sb.append(c);
            } else if (sb.charAt(sb.length() - 1) != ' ') {
                sb.append(c);
            }

            ++left;
        }
        return sb;
    }

    public void reverse(StringBuilder sb, int left, int right) {
        while (left < right) {
            char tmp = sb.charAt(left);
            sb.setCharAt(left++, sb.charAt(right));
            sb.setCharAt(right--, tmp);
        }
    }

    public void reverseEachWord(StringBuilder sb) {
        int n = sb.length();
        int start = 0, end = 0;

        while (start < n) {
            // 循环至单词的末尾
            while (end < n && sb.charAt(end) != ' ') {
                ++end;
            }
            // 翻转单词
            reverse(sb, start, end - 1);
            // 更新start,去找下一个单词
            start = end + 1;
            ++end;
        }
    }
}

方法三:双端队列

class Solution {
    public String reverseWords(String s) {
        int left = 0, right = s.length() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s.charAt(left) == ' ') {
            ++left;
        }

        // 去掉字符串末尾的空白字符
        while (left <= right && s.charAt(right) == ' ') {
            --right;
        }

        Deque<String> d = new ArrayDeque<String>();
        StringBuilder word = new StringBuilder();
        
        while (left <= right) {
            char c = s.charAt(left);
            if ((word.length() != 0) && (c == ' ')) {
                // 将单词 push 到队列的头部
                d.offerFirst(word.toString());
                word.setLength(0);
            } else if (c != ' ') {
                word.append(c);
            }
            ++left;
        }
        d.offerFirst(word.toString());

        return String.join(" ", d);
    }
}

11. 字符串变形(简单)

11.1. 题目描述

11.2. 解题思路

方法一:双逆转(推荐使用)

Java代码实现:

import java.util.*;
public class Solution {
    public String trans(String s, int n) {
        if(n==0) 
            return s;
        StringBuffer res=new StringBuffer();
        for(int i = 0; i < n; i++){
            //大小写转换
            if(s.charAt(i) <= 'Z' && s.charAt(i) >= 'A')   
                res.append((char)(s.charAt(i) - 'A' + 'a'));
            else if(s.charAt(i) >= 'a' && s.charAt(i) <= 'z') 
                res.append((char)(s.charAt(i) - 'a' + 'A'));
            else 
                //空格直接复制
                res.append(s.charAt(i));  
        } 
        //翻转整个字符串
        res = res.reverse();
        for (int i = 0; i < n; i++){
            int j = i;
            //以空格为界,二次翻转
            while(j < n && res.charAt(j) != ' ')  
                j++;
            String temp = res.substring(i,j);
            StringBuffer buffer = new StringBuffer(temp);
            temp = buffer.reverse().toString();
            res.replace(i,j,temp);
            i = j;
        }
        return res.toString();
    }
}

方法二:分割字符串+栈(扩展思路)

java代码实现:

import java.util.*;
public class Solution {
    public String trans(String s, int n) {
        if(n==0) 
            return s;
        StringBuffer res=new StringBuffer();
        for (int i = 0; i < n; i++){
            //大小写转换
            if(s.charAt(i) <= 'Z' && s.charAt(i) >= 'A')   
                res.append((char)(s.charAt(i) - 'A' + 'a'));
            else if(s.charAt(i) >= 'a' && s.charAt(i) <= 'z') 
                res.append((char)(s.charAt(i) - 'a' + 'A'));
             else 
                //空格直接复制
                res.append((char)(s.charAt(i)));  
        }
        Stack<String> temp=new Stack<String>();
        for (int i = 0; i < n; i++){
            int j = i;
            //以空格为界,分割单词
            while(j < n && res.charAt(j) != ' ')  
                j++;
            //单词进栈
            temp.push((String)(res.substring(i, j)));  
            i = j;
        }
        //排除结尾空格的特殊情况
        if(s.charAt(n - 1) == ' ')  
            res = new StringBuffer(" ");
        else
            res = new StringBuffer();
        //栈遵循先进后厨,单词顺序是反的
        while(!temp.empty()){   
            res.append(temp.peek());
            temp.pop();
            if(!temp.empty())
                res.append(" ");
        }
        return res.toString();
    }
}

12. 最长公共前缀

12.1. 题目描述

12.2. 解题思路

方法一:遍历查找(推荐使用)

Java代码实现:

import java.util.*;
public class Solution {
    public String longestCommonPrefix (String[] strs) {
        int n = strs.length;
        //空字符串数组
        if(n == 0) 
            return "";
        //遍历第一个字符串的长度
        for(int i = 0; i < strs[0].length(); i++){ 
            char temp = strs[0].charAt(i); 
            //遍历后续的字符串
            for(int j = 1; j < n; j++) 
                //比较每个字符串该位置是否和第一个相同
                if(i == strs[j].length() || strs[j].charAt(i) != temp) 
                    //不相同则结束
                    return strs[0].substring(0, i); 
        }
        //后续字符串有整个字一个字符串的前缀
        return strs[0]; 
    }
}

13. 验证IP地址

13.1. 题目描述

13.2. 解题思路

方法一:分割字符串比较法(推荐使用)

java代码实现:

import java.util.*;
public class Solution {
    boolean isIPv4 (String IP) {
        if(IP.indexOf('.') == -1){
            return false;
        }
        String[] s = IP.split("\\.");  
        //IPv4必定为4组
        if(s.length != 4)  
            return false;
        for(int i = 0; i < s.length; i++){
            //不可缺省,有一个分割为零,说明两个点相连
            if(s[i].length() == 0)  
                return false;
            //比较数字位数及不为零时不能有前缀零
            if(s[i].length() < 0 || s[i].length() > 3 || (s[i].charAt(0)=='0' && s[i].length() != 1))  
                return false;
            int num = 0;
            //遍历每个分割字符串,必须为数字
            for(int j = 0; j < s[i].length(); j++){  
                char c = s[i].charAt(j);
                if (c < '0' || c > '9') 
                    return false;
            //转化为数字比较,0-255之间
            num = num * 10 + (int)(c - '0');  
            if(num < 0 || num > 255) 
                return false;
            }
        }    
        return true;
    }
    boolean isIPv6 (String IP) {
        if (IP.indexOf(':') == -1) {
            return false;
        }
        String[] s = IP.split(":",-1);
        //IPv6必定为8组
        if(s.length != 8){  
            return false;
        }
        for(int i = 0; i < s.length; i++){ 
            //每个分割不能缺省,不能超过4位
            if(s[i].length() == 0 || s[i].length() > 4){ 
                return false; 
            }
            for(int j = 0; j < s[i].length(); j++){
                //不能出现a-fA-F以外的大小写字符
                char c = s[i].charAt(j);
                boolean expr = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ;
                if(!expr){
                    return false;
                }
            }
        }
        return true;
    }
    String solve(String IP) {
        if(isIPv4(IP))
            return "IPv4";
        else if(isIPv6(IP))
            return "IPv6";
        return "Neither";
    }
}

方法二:正则表达式(扩展思路)

Java代码实现:

import java.util.regex.Pattern;
public class Solution {
    String solve(String IP) {
        //正则表达式限制0-255 且没有前缀0 四组齐全
        String ipv4="(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
        Pattern ipv4_pattern = Pattern.compile(ipv4);
        //正则表达式限制出现8组,0-9a-fA-F的数,个数必须是1-4个
        String ipv6="([0-9a-fA-F]{1,4}\\:){7}[0-9a-fA-F]{1,4}";
        Pattern ipv6_pattern = Pattern.compile(ipv6);
        //调用正则匹配函数
        if (ipv4_pattern.matcher(IP).matches()) 
            return "IPv4";
        else if (ipv6_pattern.matcher(IP).matches()) 
            return "IPv6";
        else return "Neither";
    }
}

14. 大数加法

14.1. 题目描述

14.2. 解题思路

方法一:模拟法(建议使用)

Java代码实现:

import java.util.*;
public class Solution {
    public String solve (String s, String t) {
         //若是其中一个为空,返回另一个
        if(s.length()<=0)
            return t;
        if(t.length()<=0)
            return s;
        //让s为较长的,t为较短的
        if(s.length() < t.length()){ 
            String temp = s;
            s = t;
            t = temp;
        }
        int carry = 0; //进位标志
        char[] res = new char[s.length()];
        //从后往前遍历较长的字符串
        for(int i = s.length() - 1; i >= 0; i--){ 
            //转数字加上进位
            int temp = s.charAt(i) - '0' + carry; 
            //转较短的字符串相应的从后往前的下标
            int j = i - s.length() + t.length(); 
            //如果较短字符串还有
            if(j >= 0) 
                //转数组相加
                temp += t.charAt(j) - '0'; 
            //取进位
            carry = temp / 10; 
            //去十位
            temp = temp % 10; 
            //修改结果
            res[i] = (char)(temp + '0'); 
        }
        String output = String.valueOf(res);
        //最后的进位
        if(carry == 1) 
            output = '1' + output;
        return output;
    }
}

15. 无重复字符的最长子串

15.1. 题目描述

15.2. 解题思路

方法一:滑动窗口

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;
    }
}

16. 找到字符串中所有字母异位词(中等)

16.1. 题目描述

16.2. 解题思路

方法一:滑动窗口

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int sLen = s.length(), pLen = p.length();

        if (sLen < pLen) {
            return new ArrayList<Integer>();
        }

        List<Integer> ans = new ArrayList<Integer>();
        int[] sCount = new int[26];
        int[] pCount = new int[26];
        for (int i = 0; i < pLen; ++i) {
            ++sCount[s.charAt(i) - 'a'];
            ++pCount[p.charAt(i) - 'a'];
        }

        if (Arrays.equals(sCount, pCount)) {
            ans.add(0);
        }

        for (int i = 0; i < sLen - pLen; ++i) {
            --sCount[s.charAt(i) - 'a'];
            ++sCount[s.charAt(i + pLen) - 'a'];

            if (Arrays.equals(sCount, pCount)) {
                ans.add(i + 1);
            }
        }

        return ans;
    }
}

方法二:优化的滑动窗口

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int sLen = s.length(), pLen = p.length();

        if (sLen < pLen) {
            return new ArrayList<Integer>();
        }

        List<Integer> ans = new ArrayList<Integer>();
        int[] count = new int[26];
        for (int i = 0; i < pLen; ++i) {
            ++count[s.charAt(i) - 'a'];
            --count[p.charAt(i) - 'a'];
        }

        int differ = 0;
        for (int j = 0; j < 26; ++j) {
            if (count[j] != 0) {
                ++differ;
            }
        }

        if (differ == 0) {
            ans.add(0);
        }

        for (int i = 0; i < sLen - pLen; ++i) {
            if (count[s.charAt(i) - 'a'] == 1) {  // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同
                --differ;
            } else if (count[s.charAt(i) - 'a'] == 0) {  // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同
                ++differ;
            }
            --count[s.charAt(i) - 'a'];

            if (count[s.charAt(i + pLen) - 'a'] == -1) {  // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同
                --differ;
            } else if (count[s.charAt(i + pLen) - 'a'] == 0) {  // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同
                ++differ;
            }
            ++count[s.charAt(i + pLen) - 'a'];
            
            if (differ == 0) {
                ans.add(i + 1);
            }
        }

        return ans;
    }
}

17. 定长子串中元音的最大数目(中等)

17.1. 题目描述

17.2. 解题思路

方法一:滑动窗口

class Solution {
    public int maxVowels(String s, int k) {
        int n = s.length();
        int vowel_count = 0;
        for (int i = 0; i < k; ++i) {
            vowel_count += isVowel(s.charAt(i));
        }
        int ans = vowel_count;
        for (int i = k; i < n; ++i) {
            vowel_count += isVowel(s.charAt(i)) - isVowel(s.charAt(i - k));
            ans = Math.max(ans, vowel_count);
        }
        return ans;
    }

    public int isVowel(char ch) {
        return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' ? 1 : 0;
    }
}

18. 判断是否为回文字符串

18.1. 题目描述

18.2. 解题思路

方法一:首尾依次比较法(推荐使用)

Java代码实现:

import java.util.*;
public class Solution {
    public boolean judge (String str) {
        //首指针
        int left = 0; 
        //尾指针
        int right = str.length() - 1;
        //首尾往中间靠  
        while(left < right){  
            //比较前后是否相同
            if(str.charAt(left) != str.charAt(right)) 
                return false;
            left++;
            right--;
        }
        return true;
    }
}

方法二:反转字符串比较法(扩展思路)

import java.util.*;
public class Solution {
    public boolean judge (String str) {
        StringBuffer temp = new StringBuffer(str);
        //反转字符串
        String s = temp.reverse().toString();
        //比较字符串是否相等
        if(s.equals(str))
            return true;
        return false;
    }
}

19. 最小覆盖子串(较难)

19.1. 题目描述

19.2. 解题思路

方法一:哈希表匹配(推荐使用)

Java代码实现:

import java.util.*;
public class Solution {
    //检查是否有小于0的
    boolean check(int[] hash) { 
        for (int i = 0; i < hash.length; i++) {
            if (hash[i] < 0)
                return false;
        }
        return true;
    };
    
    public String minWindow (String S, String T) {
        int cnt = S.length() + 1;
        //记录目标字符串T的字符个数
        int[] hash = new int[128]; 
        for(int i = 0; i < T.length(); i++)
        //初始化哈希表都为负数,找的时候再加为正
            hash[T.charAt(i)] -= 1; 
        int slow = 0, fast = 0;  
        //记录左右区间
        int left = -1, right = -1;  
        for(; fast < S.length(); fast++){
            char c = S.charAt(fast);
            //目标字符匹配+1
            hash[c]++;
            //没有小于0的说明都覆盖了,缩小窗口
            while(check(hash)){  
                //取最优解
                if(cnt > fast - slow + 1){ 
                    cnt = fast - slow + 1;  
                    left = slow;
                    right = fast;
                }
                c = S.charAt(slow);
                //缩小窗口的时候减1
                hash[c]--; 
                //窗口缩小
                slow++;      
            }
        }
        //找不到的情况
        if(left == -1)     
            return "";
        return S.substring(left, right + 1);
    }
}

20. 反转字符串(入门)

20.1. 题目描述

20.2. 解题思路

解法一

import java.util.*;
public class Solution {
    public String solve (String str) {
        char[] ans = str.toCharArray();
        int len = str.length();
        for(int i = 0 ; i < len ;i++)
        {
                ans[i] = str.charAt(len-1-i);
        }
        return new String(ans);
    }
}
解法二

import java.util.*;
public class Solution {
    public String solve (String str) {
        char[] cstr = str.toCharArray();
        int len = str.length();
        for(int i = 0 ; i < len/2 ;i++)
        {
                char t = cstr[i];
                cstr[i] = cstr[len-1-i];
                cstr[len-1-i]=t;
        }
        return new String(cstr);
    }
}
解法三

直接调用库函数

import java.util.*;
public class Solution {
    public String solve (String str) {
        StringBuffer sb =new StringBuffer(str);//此方法针对的是io流,不能针对字符串。
        return sb.reverse().toString();
    }
}

http://www.kler.cn/a/529083.html

相关文章:

  • curope python安装
  • 开源智慧园区管理系统对比五款主流产品探索智能运营新模式
  • leetcode——验证二叉搜索树(java)
  • ROS-IMU
  • 向上调整算法(详解)c++
  • C++范围for和auto关键字
  • 每日 Java 面试题分享【第 18 天】
  • Java - 引用类型:强引用、软引用、弱引用和虚引用详解
  • java CountDownLatch和CyclicBarrier
  • Spring AOP 入门教程:基础概念与实现
  • ASP.NET Core 启动并提供静态文件
  • 动态规划两个数组dp问题系列一>不相交的线
  • 一文讲解Java中的HashMap
  • 快速提升网站收录:如何设置网站标签?
  • pandas中的apply方法使用
  • 【漫话机器学习系列】074.异方差(Heteroscedasticity)
  • 【Linux】23.进程间通信(2)
  • 局域网文件互传:手机与电脑的便捷传输利器
  • 《Ollama与DeepSeek》
  • 力扣-链表-142 环形链表Ⅱ
  • AI(计算机视觉)自学路线
  • 【模拟汽笛ISIS】2022-9-15
  • BUUCTF [Black Watch 入群题]PWN1 题解
  • JAVA学习-练习试用Java实现“使用Swing创建一个带有按钮的窗口”
  • 一些计算机零碎知识随写(25年2月)
  • 论文和代码解读:RF-Inversion 图像/视频编辑技术