LeeCode初级算法字符串部分九道题

系列文章目录


1.反转字符串

1.1 原创

这道题很简单,直接从字符串的两端互换元素即可,想要降低空间复杂度需要考虑特殊情况

package primary.character_string;

import java.util.Arrays;

/**
 * @Description:反转字符串
 * @Author Mr.Cui
 * @Date 2022/6/9
 */
public class string_01 {
    public static void reverseString(char[] s) {
        //只要加上这个判断条件就可以减少很多使用空间
        if (s == null || s.length < 2) {
            return;
        }
        int i=0;
        int j=s.length-1;
        while(i<j){
            char x=s[i];
            s[i]=s[j];
            s[j]=x;
            i++;
            j--;
        }
    }

    public static void main(String[] args) {
        char[] s={'2','2','3','4','5','a'};
        reverseString(s);
        System.out.println(Arrays.toString(s));
    }
}

1.2 转载

利用异或两次相同的数即可抵消不用创建中间变量1的情况下就可完成交换

package primary.character_string;

/**
 * @Description:第二次见识到了位运算的强大,这个方法看起来很炫酷,而且不需要创建额外中间值,节省了空间
 * @Author Mr.Cui
 * @Date 2022/6/9
 */
public class string_01better {
    public void reverseString(char[] s) {
        int left = 0, right = s.length - 1;
        while (left < right) {
            s[left] ^= s[right];
            s[right] ^= s[left];
            s[left++] ^= s[right--];
        }
    }

//    作者:lzhlyle
//    链接:https://leetcode.cn/problems/reverse-string/solution/ji-xian-sheng-kong-jian-by-lzhlyle/
//    来源:力扣(LeetCode)
//    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}

2.整数反转

2.1普通解法

这道题唯一需要考虑的是特殊情况,解释如下

在这里插入图片描述

package primary.character_string;

/**
 * @Description:整数反转
 * @Author Mr.Cui
 * @Date 2022/6/9
 */
public class string_02 {
    public int reverse(int x) {
        long res = 0;
        while (x != 0) {
            res = res * 10 + x % 10;
            x /= 10;
        }
        return (int) res == res ? (int) res : 0; //这里判断是否超出范围了,超出范围int只会取前32位
    }


}

3.字符串中的第一个唯一字符

3.1哈希表方法

思路是先把所有字符放到哈希表里,再重新遍历,和原来的字符串对比,只要value和之前不一样说明发生了哈希冲突进行了覆盖,则该值出现过两次,否则返回该值,如果遍历完都没有则表示不存在.

package primary.character_string;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:字符串中的第一个唯一字符
 * @Author Mr.Cui
 * @Date 2022/6/13
 */
public class string_03 {
    public static int firstUniqChar(String s) {
        int l=s.length();
        if(l==1){
            return 0;
        }
        else if(l==2){
            if (s.charAt(0)!=s.charAt(1)){
                return 0;
            }
        }
        else {
            Map<Integer, Integer> map = new HashMap<>();

            for (int i = 0; i < l; i++) {
                map.put(new Integer(s.charAt(i)), i);
                System.out.println(map);
            }
            System.out.println(map);
            System.out.println(" ===========");
            for (int i = 0; i < l; i++) {
                if (map.get(new Integer(s.charAt(i)))!=null){
                    if (map.get(new Integer(s.charAt(i)))!= i){
                        map.remove(new Integer(s.charAt(i)));

                        System.out.println(map);
                        continue;
                    }else
                    return i;
                }


            }

        }
        return -1;
    }

    public static void main(String[] args) {
        String s="aabb";
        System.out.println(firstUniqChar(s));
    }


}

3.2优化写法

一个从前查找,一个从后查找,如果下标相等,说明只出现了一次

package primary.character_string;

/**
 * @Description:看完这种写法,我感觉我像个傻子一样,写了三个小时
 * @Author Mr.Cui
 * @Date 2022/6/13
 */
public class string_03bettter {
    public int firstUniqChar(String s) {
        for (int i = 0; i < s.length(); i++)
            if (s.indexOf(s.charAt(i)) == s.lastIndexOf(s.charAt(i)))
                return i;
        return -1;
    }

//    作者:数据结构和算法
//    链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xn5z8r/?discussion=6TyKA7
//    来源:力扣(LeetCode)
//    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}

4.有效的字母异位词

4.1常规写法

首先判断两个字符串长度是否相等,不相等则返回false
将表示每个字符的ascii码放入数组中再进行排序,最后比较得出结果

package primary.character_string;

import java.util.Arrays;

/**
 * @Description:有效的字母异位词
 * @Author Mr.Cui
 * @Date 2022/6/14
 */
public class string_041有效的字母异位词 {
    public static boolean isAnagram(String s, String t) {
        if (s.length()!=t.length()){
            return false;
        }
        int[] s1 = new int[s.length()], t1 = new int[t.length()];
        for (int i = 0; i < s.length(); i++) {
            s1[i] = s.charAt(i) - '0';
            t1[i] = t.charAt(i) - '0';
        }
        Arrays.sort(s1);
        Arrays.sort(t1);
        for (int i = 0; i < s1.length; i++) {
            if (s1[i] != t1[i]) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        String s = "anagra", t = "nagaram";
        System.out.println(isAnagram(s, t));
    }
}

4.2 优化写法

先把两个字符串转化为字符数组,然后再对这两个字符数组进行排序,因为相同的字符在排序之后肯定是挨着的,最后再比较这两个排序后的数组的元素是否相同。

package primary.character_string;

import java.util.Arrays;

/**
 * @Description:先排序在比较
 * @Author Mr.Cui
 * @Date 2022/6/14
 */
public class string_042better {
    public static boolean isAnagram(String s, String t) {
        char[] sChar = s.toCharArray();
        char[] tChar = t.toCharArray();
        //对两个字符串中的字符进行排序
        Arrays.sort(sChar);
        Arrays.sort(tChar);
        return Arrays.equals(sChar, tChar);
    }
//    作者:数据结构和算法
//    链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xn96us/?discussion=2dBKuA
//    来源:力扣(LeetCode)
//    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}

5验证回文数

思路就是从两头遍历,跳过不是字符和数字的位置.

package primary.character_string;

/**
 * @Description:
 * @Author Mr.Cui
 * @Date 2022/6/15
 */
public class string_051验证回文串 {
    public static boolean isPalindrome(String s) {
        if (s.length() == 0)
            return true;
        int left = 0, right = s.length() - 1;
        while (left < right) {
            //因为题中说了,只考虑字母和数字,所以不是字母和数字的先过滤掉
            while (left < right && !Character.isLetterOrDigit(s.charAt(left)))
                left++;
            while (left < right && !Character.isLetterOrDigit(s.charAt(right)))
                right--;
            //然后把两个字符变为小写,在判断是否一样,如果不一样,直接返回false
            if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right)))
                return false;
            left++;
            right--;
        }
        return true;
    }

    public static void main(String[] args) {
        String s="A man, a plan, a canal: Panama";
        System.out.println(isPalindrome(s));
    }
}

6.字符串转换整数

解题思路

定义一个指针index 指向正在判断的字符

  • 先把空格去掉index++
  • 再判断是否有符号 index++ 并保留
  • 遇到非数字直接return
  • 先允许越界,越界后数据肯定和期望值不同,整除10后和原来的数比较即可,根据符号返回对应的最值
  • 返回结果时,带上符号
public static int myAtoi(String s) {
        char[] chars = s.toCharArray();
        int length = chars.length;
        int index = 0;
        // 先去除空格
        while (index < length && chars[index] == ' '){
            index++;
        }
        // 极端情况 "  " 和""
        if(index >= length){
            return 0;
        }
        // 再判断符号
        int sign =  1;
        if(chars[index] == '-' || chars[index] == '+'){
            if(chars[index] == '-'){
                sign = -1;
            }
            index++;
        }
        int result = 0;
        int temp = 0;
        while (index < length){
            int num = chars[index] - '0';
            if(num > 9 || num < 0){
                break;
            }
            temp = result;    //10
            result = result * 10 + num;
            // 越界后,数值和期望数值发生变化,取余再除10获取原始值,比对判断
            if(result/10 !=temp){
                if(sign > 0){
                    return Integer.MAX_VALUE;
                }else {
                    return Integer.MIN_VALUE;
                }
            }
            index++;
        }
        return result*sign;
    }

7.字符串匹配

题解

这道题主要用到了KMP算法
在这里插入图片描述
这里我补充一点:注意真前缀和真后缀的定义,比如说aab他的真前缀为aa,a,真后缀为b,ab,也就是说不包含字符串本身,
我们举个例子说明:字符串 aabaaab 的前缀函数值依次为 0,1,0,1,2,2,3。

在这里插入图片描述
转载于https://blog.csdn.net/qq_46092061/article/details/119857352
有了前缀函数,我们就可以快速地计算出模式串在主串中的每一次出现。

这样我们可以将代码实现分为两部分:

第一部分是求 needle 部分的前缀函数,我们需要保留这部分的前缀函数值。
第二部分是求 haystack 部分的前缀函数,我们无需保留这部分的前缀函数值,只需要用一个变量记录上一个位置的前缀函数值即可。当某个位置的前缀函数值等于 m 时,说明我们就找到了一次字符串 needle 在字符串 haystack 中的出现(因为此时真前缀恰为字符串 needle,真后缀为以当前位置为结束位置的字符串 haystack 的子串),我们计算出起始位置,将其返回即可。

求解next数组前要懂得以下几个概念:
1、前缀:包含首位字符但不包含末位字符的子串。
2、后缀:包含末位字符但不包含首位字符的子串。
3、next数组定义:当主串与模式串的某一位字符不匹配时,模式串要回退的位置。
4、next[j]:其值–第j位字符前面j-1位字符组成的子串的前后缀重合字符数+1
规律:
1、next[们]的值每次最多增加1
2、模式串的最后一位字符不影响next数组的结果
B站视频讲解KMP代码

代码

public static int strStr(String haystack, String needle) {

        int n = haystack.length(), m = needle.length();
        if (m == 0)
            return 0;
        int[] next = new int[m];
        next[0] = 0;  // 也有初始-1的next数组
        for (int i = 1, j = 0; i < m; i++) {  // 每一轮j都从0开始
            while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
                j = next[j - 1];  // 回退到上一个位置的公共前后缀
            }
            if (needle.charAt(i) == needle.charAt(j)) {
                j++;  // 长度++
            }
            next[i] = j;  // 当前位置最长公共前后缀
        }
        for (int i = 0, j = 0; i < n; i++) {
            while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
                j = next[j - 1];
            }
            if (haystack.charAt(i) == needle.charAt(j)) {
                j++;  // 长度++
            }
            if (j == m) {
                return i - m + 1;
            }
        }
        return -1;
    }

KMP算法让我有点怀疑人生,先过去把,过几年再看可能就懂了…

8.外观数列

思路是从左向右遍历,然后因为String是不可变的,所以用可变并且性能好的StringBuilder
将每个连续的相同数字通过append加入到sb变量中,最后返回str;

package primary.character_string;

/**
 * @Description:
 * @Author Mr.Cui
 * @Date 2022/8/21
 */
public class string_081外观数列 {
    public static String countAndSay(int n) {
        String str = "1";
        for (int i = 2; i <= n; ++i) {
            StringBuilder sb = new StringBuilder();
            int start = 0, pos = 0;
            while (pos < str.length()) {
                while(pos<str.length() && str.charAt(pos) == str.charAt(start)){
                    pos++;
                }

                sb.append(Integer.toString(pos-start)).append(str.charAt(start));
                start = pos;
            }
            str = sb.toString();
        }
        return str;
    }

    public static void main(String[] args) {
        int i = 4;
        System.out.println(countAndSay(i));
    }
}

9.最长公共前缀

思路是从字符串数组中取其中的一个字符串从后往前依次缩减字符,再用String自带的startwith方法进行匹配即可

package primary.character_string;

/**
 * @Description:
 * @Author Mr.Cui
 * @Date 2022/8/24
 */
public class 最长公共前缀 {
    public static String longestCommonPrefix(String[] strs) {
        if(strs.length==0)return "";
        //公共前缀比所有字符串都短,随便选一个先
        String s=strs[0];
        for (String string : strs) {
            while(!string.startsWith(s)){
                if(s.length()==0)return "";
                //公共前缀不匹配就让它变短!
                s=s.substring(0,s.length()-1);
            }
        }
        return s;
    }

    public static void main(String[] args) {
        String[] s = {"flower","flow","flight"};
        System.out.println(longestCommonPrefix(s));
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值