字符串类算法题

1、字符处理:

1)字符过滤:只保留大小字母和数字:

StringBuffer sgood = new StringBuffer();
int length = s.length();
for (int i = 0; i < length; i++) {
    char ch = s.charAt(i);
    if (Character.isLetterOrDigit(ch)) {
        sgood.append(Character.toLowerCase(ch));
    }
}

2)大小写转换:

Character.toLowerCase(char ch)

2、字母统计:

1)所有字符都要统计

int[] count = new int[128];
for(int i=0; i < A.length(); i++)
    count[A.charAt(i)]++;

2)只统计小写字母或大写字母 

int[] count = new int[26];
for(int i=0; i < A.length(); i++)
    count[A.charAt(i)-'a']++;

3、回文字符串:正读反读都一样的字符串

1)判断是否是回文字符串

常见的做法是使用双指针。定义左右指针,初始时分别指向字符串的第一个字符和最后一个字符,每次判断左右指针指向的字符是否相同,如果不相同,则不是回文串;如果相同,则将左右指针都往中间移动一位,直到左右指针相遇,则字符串是回文串。

fig1

class Solution {
    public boolean validPalindrome(String s) {
        int low = 0, high = s.length() - 1;
        while (low < high) {
            char c1 = s.charAt(low), c2 = s.charAt(high);
            if (c1 != c2) 
                return false;
        }
        return true;
    }
}

 在允许最多删除一个字符的情况下,同样可以使用双指针,通过贪心算法实现。初始化两个指针 low 和 high 分别指向字符串的第一个字符和最后一个字符。每次判断两个指针指向的字符是否相同,如果相同,则更新指针,令 low = low + 1 和 high = high - 1,然后判断更新后的指针范围内的子串是否是回文字符串。如果两个指针指向的字符不同,则两个字符中必须有一个被删除,此时我们就分成两种情况:即删除左指针对应的字符,留下子串 s[low + 1], s[low + 1], ..., s[high],或者删除右指针对应的字符,留下子串 s[low], s[low + 1], ..., s[high - 1]。当这两个子串中至少有一个是回文串时,就说明原始字符串删除一个字符之后就以成为回文串。

fig1

class Solution {
    public boolean validPalindrome(String s) {
        int low = 0, high = s.length() - 1;
        while (low < high) {
            char c1 = s.charAt(low), c2 = s.charAt(high);
            if (c1 == c2) {
                low++;
                high--;
            } else {
                boolean flag1 = true, flag2 = true;
                for (int i = low, j = high - 1; i < j; i++, j--) {
                    char c3 = s.charAt(i), c4 = s.charAt(j);
                    if (c3 != c4) {
                        flag1 = false;
                        break;
                    }
                }
                for (int i = low + 1, j = high; i < j; i++, j--) {
                    char c3 = s.charAt(i), c4 = s.charAt(j);
                    if (c3 != c4) {
                        flag2 = false;
                        break;
                    }
                }
                return flag1 || flag2;
            }
        }
        return true;
    }
}

2)判断最长回文字串的长度

有两个点要注意:

1.回文串中每个字母都会使用偶数次(统计出所有字母的出现次数后,采用/2*2的方法,将出现奇数次的-1,出现偶数次的保持不变

for(int v:alphabet){
    max += v/2*2;
}

2.中文线使用竖线|(回文串长度是偶数)还是字母(回文串长度是奇数),如果某个字母出现了奇数次且当前的回文串长度是偶数,则回文串长度+1,代码如下

for(int v:alphabet){
    max += v/2*2;
    if((v%2==1&&max%2==0))
        max += 1;
}

4、上升下降字符串:

给定第一个字符串,第一遍从小到大遍历末尾,第二遍从大到小遍历并移动到末尾,如果每次遍历时最小或者最大字符不止一个 ,可以选择其中任意一个。

输入:s = "aaaabbbbcccc"
输出:"abccbaabccba"
解释:第一轮的步骤 1,2,3 后,结果字符串为 result = "abc"
第一轮的步骤 4,5,6 后,结果字符串为 result = "abccba"
第一轮结束,现在 s = "aabbcc" ,我们再次回到步骤 1
第二轮的步骤 1,2,3 后,结果字符串为 result = "abccbaabc"
第二轮的步骤 4,5,6 后,结果字符串为 result = "abccbaabccba"

image.png

class Solution {
    public String sortString(String s) {
        //相当于26个桶
        int[] ch = new int[26];
        
        //把s中的字符分别放到对应的桶里
        for(int i=0; i<s.length();i++){
            ch[s.charAt(i)-'a'] ++;
        }
    
        //存储计算的结果
        StringBuffer res = new StringBuffer();
        while(res.length()<s.length()){

            //先从左往右找,遍历26个桶,如果当前桶不为空,
            //就从当前桶里拿出一个元素出来
            for(int i =0;i<26;i++){
                if(ch[i]>0){
                    res.append((char) (i + 'a'));
                    ch[i]--;//拿出之后桶中元素的个数要减1
                }
            }

            //从右往左拿,同上
            for(int i=25;i>-1;i--){
                if(ch[i]>0){
                    res.append((char) (i + 'a'));
                    ch[i]--;
                }
            }
        }
        //把结果转化为字符串
        return res.toString();
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值