算法学习【2】字符个数统计

本文探讨了华为机试题库中的一道字符个数统计问题,指出使用双层循环会导致错误,因为计算结果包含组合重复。提出通过初始化输入字符串长度的数组并标记重复字符为-1,或者使用boolean数组结合ASCII码限制来优化空间。同时,介绍了使用HashSet和HashMap等集合框架实现去重的方案。

      牛客网的华为机试题库有一道题:字符个数统计。


      若直接用两个for循环则会发生错误,错误的程序如下:

import java.util.Scanner;
public class Main{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		while(sc.hasNextLine()){
			String str = sc.nextLine();
			int n = 0;
			for(int i=0;i<str.length()-1;i++){
				for(int j=i+1;j<str.length();j++){
					if(str.charAt(i) == str.charAt(j)){
						n++;
					}
				}
			}
			System.out.println("重复字符个数:"+n);
			System.out.println("不同字符统计:"+(str.length()-n));
		}
	}
}

输出结果:

aasd
重复字符个数:1
不同字符统计:3
asd
重复字符个数:0
不同字符统计:3
aaasd
重复字符个数:3
不同字符统计:2
aaaasd
重复字符个数:6
不同字符统计:0

      最近冒泡法写习惯了,就导致了这样的错误,错误根源在当有三个以上的字符出现时,计算结果为组合C(n, m) = n!/m!/(n-m)!,出现重复情况。

      因此,建立一个输入字符串长度的数组,用于统计每个字符的个数, 同时将数组中重复字符对应位置的值设置为-1,结果如下:

import java.util.Scanner;
public class MyCode6 {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		String str = sc.nextLine();
		sc.close();
		int len = str.length();
		
		int[] count = new int[len];
		for(int i=0;i<len;i++){
			for(int j=0;j<len;j++){			
				if(str.charAt(i)==str.charAt(j)){
					if(i>j){
						count[i]=-1;//重复元素
						break;
					}else{
						count[i]++;
					}
				}
			}
		}
		
		int sum = 0;
		for(int k=0;k<len;k++){
			if(count[k]>0)
				sum++;
		}
		System.out.println(sum);
		
	}
}
      以上程序经验证正确。


     而题目并未要求统计各个字符的个数,因此可以用boolean类型的数组表示,节约空间。

import java.util.Scanner;
public class Main{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		String str = sc.nextLine();
		sc.close();
		int len = str.length();
		boolean[] count = new boolean[len];
		
		for(int i=0;i<len;i++){
			for(int j=0;j<len;j++){			
				if(str.charAt(i)==str.charAt(j)){
					if(i>j){
						
					}else if(i<j){
						count[i] = true;//重复元素
					}
				}
			}
		}
		
		int sum = 0;
		for(int k=0;k<len;k++){
			if(count[k]==false)
				sum++;
		}
		System.out.println(sum);
		
	}
}
      以上程序经验证正确。


      但当输入的字符串过长时,建立的数组也就越长,有可能超过允许长度。由题可知,输入字符的ASCii码值都在0~127范围内,因此可以建立一个长度为128的boolean数组,判断每个字符是否存在。

import java.util.Scanner;

public class MyCode5 {
public static void main(String args[]) {
	
	Scanner sc = new Scanner(System.in);
	String str = sc.nextLine();
	sc.close();
	boolean [] arr=new boolean[128];
	
        for(int i=0;i<str.length();i++){
            int t=(int)str.charAt(i);
            if(t>127){
                continue;
            }
            arr[t]=true;
        }
        
        int sum=0;
        for(int i=0;i<arr.length;i++){
            if(arr[i]){
            	sum++;
            }
        }
        
        System.out.println(sum);
	}
}

      以上程序经验证正确。

   

      除此之外,我们还可以使用集合框架来简化程序。

     例如HashSet类,它实现了set接口,而set接口不允许存在重复的元素。

import java.util.*;

public class Main{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		String str = sc.nextLine();
		sc.close();
		
		HashSet<Character> hs = new HashSet<Character>();
		for(int i=0;i<str.length();i++){
			hs.add(str.charAt(i));
		}
		
		System.out.println(hs.size());
	}
}
      以上程序经验证正确。

      例如映射类HashMap 类,它实现了Map接口,映射(Map)要求键唯一,也可以实现去重的效果。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值