字符串集合

前言

        学了一段时间的字符串书写,今天就浅浅发个集合吧。也算做个阶段性总结,方便以后复习。这一篇字符串集合也发到了蓝桥杯刷题笔记专栏里。接下来的几个月时间里,也会发一些专栏集合,和刷题总结啥的。冲刺蓝桥杯!那我们开始字符串旅程吧!


目录

1. 门牌制作

2. 子串分值和

3. 用杂志拼接信封

4. 山

总结​编辑


1. 门牌制作

门牌制作

小蓝要为一条街的住户制作门牌号。

这条街一共有 2020 位住户,门牌号从 1 到 2020 编号。

小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、7,即需要 1 个字符 0,2 个字符 1,1 个字符 7。请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?

分析

先看一眼题目,即是统计每一个字符出现的次数,要知道从1到2020出现了几个字符2,这里列举出三种方法。

  • 方法1:暴力搜索。 我们从1~2020进行遍历,每遍历一次,就判断改数字是否出现了数字2(对该数字取余看它是否等于2),对每一次遍历后的结果进行统计,最终得到2出现的次数。
  • 方法2:字符串检索。 首先我们可以将1~2020拼接成一个字符串长串,然后遍历该字符串,判断该索引下的字符是否为2;最后统计出现的次数。
  • 方法3:字符串替换。 也是先将数字拼接成一个字符串,然后用“null”替换掉不是2的数字,最终得到的字符串长度就是出现字符2的次数。

代码如下:

public class 门牌制作 {
    public static void main(String[] args) {
        int ans1 = 0; //统计个数(需要多少个字符2)
        int ans2 = 0; //统计个数(需要多少个字符2)

        /**
         * 方法1: 暴力搜索
         */

        for(int i=1; i<=2020; i++){
            ans1 += howmany2(i);
        }
        System.out.println(ans1);

  // ------------------------------------------------------------

        /**
         * 方法2:字符串检索
         */
        String a = ""; //初始化a字符串
        for(int i = 1; i <= 2020; i++) a += i; //这里将12345……2022无缝拼接成一个很长的字符串
        for(int i = 0; i < a.length(); i++){
            if(a.charAt(i) == '2') ans2++; //注意:这里是'2',而不是2,判断匹配的是2这个字符
        }
        System.out.println(ans2);

   // ------------------------------------------------------------

        /**
         * 方法3:字符串替换
         */
        String b = "";
        for(int i = 1; i <= 2020; i++) b += i; //字符串拼接
        //replaceAll(); 把第一个的值用第二个替换,返回的长度就是有几个2
        System.out.println(b.replaceAll("[0-1]|[3-9]","").length());

    }

    public static int howmany2(int n){
        int cnt = 0; //统计个数(需要多少个字符2)
        while (n>0){
            if(n%10 == 2) cnt++;
            n /= 10;
        }
        return cnt;
    }
}

建议多去看看API,真的很有用。

2. 子串分值和

对于一个字符串S,我们定义S的分值f(S)为S 中出现的不同的字符个数。例如f("aba") = 2, f("abc") = 3, f("aaa") = 1。现在给定一个字符串S[0……n-1] (长度为n),请你计算所有S的非空字串S[i...j] (0 <= i <= j <n), f(S[i...j]) 的和是多少。

分析

这道题就是统计不同字母出现的个数。这里给出两种方法实现:

  • 方法1:字符数组。 我们可以用一个含有26个字母的 int 数组来存放26个字母出现的次数,数组长度作为每个字母的索引,从a~z。如果原字符串里出现这个字母,我们就把该字母出现的次数增加一次。最终将 int 数组里值不为0的个数统计就是不同字母出现的次数。
  • 方法2:哈希表我们知道哈希表有去重的性质,那么我们就可以将字符串加入到哈希表里(不会哈希表可以去看我的哈希表集合)。最终返回哈希表的长度即可。

上代码:

public class 子串分值和 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int ans = num1(s);
        System.out.println(ans);

    }
    //用字符数组
    private static int num1(String s){
        int[] sum = new int[26]; //里面装的是26个字母出现的次数
        for(int i=0; i < s.length(); i++){
            sum[s.charAt(i)-'a']++; 
        }
        int d = 0; //存储出现的次数
        for(int i = 0; i < 26; i++){
            if(sum[i] != 0) d++;
        }
        return d;
    }
    //用哈希表
    private static int num2(String s){
        Set<Character> set = new HashSet<>();
        for(int i = 0; i < s.length(); i++){
            set.add(s.charAt(i));
        }
        return set.size();
    }
    //用哈希表查看每个字符添加到哈希表的过程
    private static int num3(String s){
        int sum = 0;
        for(int i = 0; i < s.length(); i++){
            Set<Character> set = new HashSet<>();
            String m = "";
            for(int j = i; j < s.length(); j++){
                set.add(s.charAt(j));
                m = m + s.charAt(j);
                sum  = sum + set.size(); //哈希表是去重的
                System.out.println(m + " " + set.size());
            }
        }
        return sum;
    }
}

3. 用杂志拼接信封

实现一个算法确定能否由杂志构成信件。介绍如下:

影视剧中信件大多是从报纸或杂志上的字符剪下来拼接而成的。

杂志和信件均由字符串构成,对于给定的杂志和信件,确定信件是否可以由杂志上的字符构成。

例如杂志为 ab,信件为 aa,则不能构成。杂志为 aab,信件为 aa,则可以构成。

分析

既然是字符串集合,这里就将字符拆分做法吧。(代码里面也附上了哈希表做法)

  • 跟上一道题一样,这一道题也是可以用数组来统计每个字母出现的次数,如果杂志里字幕出现的次数小于信件里的,就不能构成。没有出现的字母次数是0;出现了1次就是1;以次类推。

上代码:

public class 杂志2 {
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        String s = sc.next(); //杂志
        String l = sc.next(); //信件
        int[] ms = new int[26],ml = new int[26];
        for(int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i); //将字符串s放入字符数组c中,c中存放的是字母
            //ms里存放的是字母,'a'-'a'=0,得到m[0]就是a的位置,然后a位置的数值+1;'b'-'a'=1,得到m[1]就是b的位置,然后b位置的数值+1;
            //如果有两个字母一样的话,那么该字母的位置上的数值就再+1,最终得到该26个字母在相应位置出现的次数
            ms[c-'a']++;
        }
        for(int i = 0; i < l.length(); i++)
        {
            char c = l.charAt(i);
            ml[c-'a']++;
        }
        //判断杂志上的字符是否可以构成信件
        for(int i = 0; i < 26; i++)
        {
            //这里也就是在比较字母出现次数的大小了
            if(ms[i] < ml[i])
            {
                System.out.println("NO");
                return;
            }
        }
        System.out.println("YES");
    }
}
public class 用杂志拼接信封
{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        String s = sc.next(); //杂志
        String l = sc.next(); //信件
        HashMap<Character,Integer> ms = new HashMap<>();
        HashMap<Character,Integer> ml = new HashMap<>();
        for(int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i); //将字符串s放入字符数组c中
            ms.put(c,ms.getOrDefault(c,0)+1); //这里对应的下标值+1,防止空指针
        }
        for(int i = 0; i < l.length(); i++)
        {
            char c = l.charAt(i); //将字符串s放入字符数组c中
            ml.put(c,ms.getOrDefault(c,0)+1);
        }
        //判断杂志上的字符是否可以构成信件
        for(char i = 'a'; i <= 'z'; i++) //这里for循环遍历字母A~Z
        {
            //如果某个字母在哈希表中存在,就返回该字母在哈希表中的下标,不存在就返回0
            //若杂志的长度小于信件的长度,则代表不能构成(这里每次是判断一个字符,依次判断每一个字符)
            //因为哈希表不能存相同的值(若相同,则会被后面的相同值覆盖),所以返回相同值最大的下标
            if(ms.getOrDefault(i,0) < ml.getOrDefault(i,0))
            {
                System.out.println("NO");
                return;
            }
        }
        System.out.println("YES");
    }
}

4. 山

第十三届蓝桥杯真题

这天小明正在学数数。

他突然发现有些止整数的形状像一挫 “山”, 比如 123565321 、 145541123565321、145541, 它 们左右对称 (回文) 且数位上的数字先单调不减, 后单调不增。

小朋数了衣久也没有数完, 他惒让你告诉他在区间 2022, 2022222022 中有 多少个数的形状像一座 “山”。

分析

       我们首先想到的方法肯定是暴力,我们从 20222022222022 遍历,对于每一个数,我们判断是否是回文串,并且是否满足是递增再递减的序列,最后统计答案 , 时间复杂度大概是 10^10 级别的,大概在本地要跑 90-100s 左右 。已经超时了,所以我们不能用这种做法。

  • 由本题题意可知我们最多能形成长度为 10的回文串,于是我们暴力枚举前五个不下降序列,偶数长度和奇数长度的不下降子序列分开维护,最后判断形成的回文串是否在 20,2022222022 区间即可。
import java.util.Collections;
import java.util.Scanner;

public class Main {
    static int ans = 0 ; //符合条件的数
    static int o[] = new int[20] ; //偶数长度的序列
    static int e[] = new int[20] ; //奇数长度的序列

    static long get(int[] s , int n) {//n为序列长度,s是一个暂存数组
        long res = 0 ;
        for(int i = 1 ; i <= n ; i ++)
            res = (res * 10 + s[i]) ;//这里就是返回序列数,res即原数
        while(res > 0 && res % 10 == 0) res /= 10 ; //因为我们前后添加了0,这里在做去0处理
        return res ;
    }

    static void dfs(int u , int last) {//u代表位数,last代表最后一位的值
        if(u == 6) {
            //判断序列是否在范围之间
            if(get(o , 10) >= 2022 && get(o , 10) <= 2022222022) ans ++ ;
            if(get(e , 9) >= 2022 && get(e , 9) <= 2022222022) ans ++ ;
            return ;
        }
        for(int i = last ; i <= 9 ; i ++) {
            //构造回文串,即对称数字
            o[u] = o[10 - u + 1] = i ;//第i位等于对称位
            e[u] = e[9 - u + 1] = i ;
            dfs(u + 1 , i) ;//循环,第十位,0~9
        }
    }
    public static void main(String[] args) {
        dfs(1 , 0) ;
        System.out.println(ans) ;
    }

}

总结

用题目来简单对字符串的运用做了一个集合,对于字符串的运用要熟练运用还是要通过多做题目,另外,API里也有很多String,Char,Arrays里面很多方法,多运用库函数更能简化我们做题的步骤。今天的分享就到这里啦!

 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王水最甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值