字符串相关算法

本文介绍了几种常见的字符串处理算法,包括最长公共前缀的两种实现方法、寻找最长回文子串的中心扩散策略、二进制求和和字符串相乘的计算逻辑,以及非对称字符串的识别和小红的ABC问题的解决方案。
摘要由CSDN通过智能技术生成

最长公共前缀

  • 两两比较
class Solution {
    public String longestCommonPrefix(String[] strs) {
        String ret = strs[0];
        for(int i = 1; i < strs.length; i++) {
            ret = findCommon(strs[i], ret);
        }
        return ret;
    }

    String findCommon(String s1, String s2) {
        int i = 0;
        while(i < Math.min(s1.length(), s2.length()) && s1.charAt(i) == s2.charAt(i)) 
            i++;
        return s1.substring(0, i);
    }
}
  • 统一比较
class Solution {
    public String longestCommonPrefix(String[] strs) {
        for(int i = 0; i < strs[0].length(); i++) {
            char tmp = strs[0].charAt(i);
            for(int j = 1; j < strs.length; j++) {
                if(i == strs[j].length() || strs[j].charAt(i) != tmp)
                    return strs[0].substring(0, i);
            }
        }
        return strs[0];
    }
}

最长回文子串

  • 中心扩散

如果⼀个子串是回⽂串,并且长度⼤于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。⼀直去除首尾到长度小于等于 2 。长度为 1 的,⾃⾝与⾃⾝就构成回⽂;而⻓度为 2 的,就要判断这两个字符是否相等了。
从这个性质可以反推,从回文串的中心开始,往左读和往右读也是⼀样的。那么可以枚举回文串的中心。
从中心向两边扩展,如果两边的字母相同,我们就可以继续扩展;如果不同,我们就停止扩展。这样只需要⼀层 for 循环,我们就可以完成先前两层 for 循环的工作量。

class Solution {
    public String longestPalindrome(String s) {
        int begin = 0, len = 0, n = s.length();
        for(int i = 0; i < n; i++) { //固定中心点
            //扩展奇数长度的子串
            int left = i, right = i;
            while(left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            }
            if(right - left - 1 > len) {
                begin = left + 1;
                len = right - left - 1;
            }
            //扩展偶数长度
            left = i; right = i + 1;
            while(left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            }
            if(right - left - 1 > len) {
                begin = left + 1;
                len = right - left - 1;
            }
        }
        return s.substring(begin, begin + len);
    }
}
  • 动态规划

以后会出动态规划相关文章,到时候附上链接

二进制求和

算法思路(模拟十进制的大数相加的过程):
模拟十进制列竖式计算两个数之和的过程。但是这里是⼆进制的求和,我们不是逢十进一,⽽是逢⼆进⼀。

class Solution {
    public String addBinary(String a, String b) {
        StringBuffer ret = new StringBuffer();
        int cur1 = a.length() - 1, cur2 = b.length() - 1, t = 0;
        while(cur1 >=  0 || cur2 >= 0 || t != 0) {
            if(cur1 >= 0) t += a.charAt(cur1--) - '0';
            if(cur2 >= 0) t += b.charAt(cur2--) - '0';
            ret.append(t % 2);
            t /= 2;
        }
        return ret.reverse().toString();
    }
}

字符串相乘

算法思路(无进位相乘然后相加,最后处理进位):

整体思路就是模拟列竖式计算两个数相乘的过程。但是为了书写代码的方便性,我们选择优化的版本,就是在计算两数相乘的时候,先不考虑进位,等到所有结果计算完毕之后,再去考虑进位。如下图:
在这里插入图片描述

class Solution {
    public String multiply(String num1, String num2) {
        //1.准备工作
        int m = num1.length(), n = num2.length();
        char[] n1 = new StringBuffer(num1).reverse().toString().toCharArray();
        char[] n2 = new StringBuffer(num2).reverse().toString().toCharArray();
        int[] tmp = new int[m + n - 1];

        //2.无进位相乘,然后相加
        for(int i = 0; i < m; i++) 
            for(int j = 0; j < n; j++)
                    tmp[i+j] += (n1[i] - '0') * (n2[j] - '0');

        //3.处理进位
        int cur = 0, t = 0;
        StringBuffer ret = new StringBuffer();
        while(cur < m + n - 1 || t != 0) {
            if(cur < m + n - 1) t += tmp[cur++];
            ret.append(t % 10);
            t /= 10;
        }

        //4.处理前导0
        while(ret.length() > 1 && ret.charAt(ret.length() - 1) == '0') 
            ret.deleteCharAt(ret.length() - 1);

        return ret.reverse().toString();
    }
}

前导0的情况也就是一个乘数为0 的情况,可以改成如下代码:

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }

        //1.准备工作
        int m = num1.length(), n = num2.length();
        char[] n1 = new StringBuffer(num1).reverse().toString().toCharArray();
        char[] n2 = new StringBuffer(num2).reverse().toString().toCharArray();
        int[] tmp = new int[m + n - 1];

        //2.无进位相乘,然后相加
        for(int i = 0; i < m; i++) 
            for(int j = 0; j < n; j++)
                    tmp[i+j] += (n1[i] - '0') * (n2[j] - '0');

        //3.处理进位
        int cur = 0, t = 0;
        StringBuffer ret = new StringBuffer();
        while(cur < m + n - 1 || t != 0) {
            if(cur < m + n - 1) t += tmp[cur++];
            ret.append(t % 10);
            t /= 10;
        }

        return ret.reverse().toString();
    }
}

非对称之美

  • 如果全是相同的字母,比如aaaaaaaa,那就输出0
  • 回文串减去1个字母就不是回文串了
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        char[] s = in.next().toCharArray();
        int n = s.length;
        boolean flag = false;
        for(int i = 1; i < n; i++) {
            if(s[i] != s[0]) {
                flag = true;
                break;
            }
        }
        if(flag) {//不是相同字符
            flag = false;
            //判断本身是不是回文
            int left = 0, right = n - 1;
            while (left < right) {
                if(s[left] == s[right]) {
                    left++;
                    right--;
                } else {
                    flag = true;
                    break;
                }
            }
            if(flag) System.out.println(n);
            else System.out.println(n-1);
        } else {//是相同字符
            System.out.println(0);
        }
    }
}

字符串分类

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        Set<String> set = new HashSet<>();

        while (n-- != 0) {
            char[] s = in.next().toCharArray();
            Arrays.sort(s);
            set.add(String.valueOf(s));
        }

        System.out.println(set.size());
    }
}

小红的ABC

因为只包含三种字符, 所以仅需判断长度为2 以及 长度为3 的子串是否是回文串即可,如果没有就返回-1

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        char[] s = in.next().toCharArray();
        
        int ret = -1;
        int n = s.length;
        for(int i = 0; i < n; i++) {
            if(i+1 < n && s[i] == s[i+1]) { // 判断长度为 2 的子串
                ret = 2;
                break;
            }
            if(i+2 < n && s[i] == s[i+2]) // 判断长度为 3 的子串
                ret = 3;
        }
        System.out.println(ret);
    }
}

旋转字符串

class Solution {
    public boolean rotateString(String s, String goal) {
        return s.length() == goal.length() && (s + s).contains(goal);
    }
}

旋转字符串(二)

import java.util.*;

public class Solution {
    public boolean solve (String A, String B) {
        int n = A.length();
        int m = B.length();
        if(n != m) return false;
        for(int i = 1; i < n; i++) {
            String s1 = A.substring(0, i);
            String s2 = A.substring(i, n);
            if((s2 + s1).equals(B)) return true;
        }
        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值