5月7日,阿里模拟笔试题,字符串去重(去重长度大于1,不管数字)
题目要求:数字不用去重,且去重的长度需要大于1.
示例输出:输入:商品质量问题我要退款我要退款,我都要退款 输出:商品质量问题我要退款,我都要退款 输入:阿里巴巴 :输出:阿里巴巴 输入:10000 输出:10000
我个人理解的输入输出:
1.输入:我要退款我要退款退款 输出:我要退款
2.输入:我只有100我只有100 输出:我只有100
3.输入:我要退款我着急我要退款我着急 输出:我要退款我着急
4.输入:我要退款我着急我着急 输出:我要退款我着急
5.输入:我要退款我着急我要退款我着急我要退款我着急 输出:我要退款我着急
6.输入:我要退款我要退款我要退款 输出:我要退款
7.输入:我要退款我要退款我要退款退款 输出:我要退款
8.输入:我要退款我着急我要退款我着急我要退款我着急我着急 输出:我要退款我着急
package netease;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.Map.Entry;
public class delrepeat {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
scan.close();
String result = solve(str);
System.out.println(result);
}
public static void addIdex(HashMap<Character, ArrayList<Integer>> record,char cur,int i){
if(!record.containsKey(cur)){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(i);
record.put(cur, list);
}else{
ArrayList<Integer> list = record.get(cur);
list.add(i);
}
}
public static String solve(String str){
char[] chars = str.toCharArray();
HashMap<Character, ArrayList<Integer>> record = new HashMap<>();
StringBuilder result = new StringBuilder();
for(int i=0;i<chars.length;i++){
char cur = chars[i];
if (cur < '0' || cur > '9'){//如果不是数字就需要判断
if(!record.containsKey(cur)){
addIdex(record,cur,i);
}else{
ArrayList<Integer> listPre = record.get(cur);
int length = listPre.size();
boolean ifrepeat = false;
for(int j=length-1;j>=0;j--){
int preIndex = listPre.get(j);
int skip = getCount(chars ,preIndex ,i);//需要跳跃的索引
if(skip>0){
System.out.println(i+" "+skip);
ifrepeat = true;
boolean flag = j==0?true:false;//判断是否record全部都要更新
//更新record
updateIdex(chars,record,flag,preIndex,i,skip);
i+=skip-1;//因为每次循环体结束后会执行i++,所以这里还得减一
break;
}
}
if(ifrepeat == true) continue;
else addIdex(record,cur,i);
}
}
System.out.println(i+" "+cur);
result.append(cur);
}
return result.toString();
}
public static int getCount(char[] chars,int preIndex ,int curIndex){
int gap = curIndex - preIndex;
if(gap<=1) return 0;//保证去重长度大于1
int count = 0;
int k;
for(k=1;k<gap;k++){//判断当前和之前,之前是否有重复,第一个不用判断,从1开始
if(curIndex+k>=chars.length)
break;
if(chars[preIndex+k]!=chars[curIndex+k])
break;
if(k==gap-1){
count++;
break;
}
}
//如果count等于1,那么就需要判断当前和之后是否有重复
if(count==1){
int temp=0;
boolean flag = true;
while(true){
int i;
for(i=0;i<gap;i++){
if(curIndex+(temp+1)*gap+i>=chars.length){
flag = false;
break;
}
if(chars[curIndex+(temp)*gap+i]!=chars[curIndex+(temp+1)*gap+i]){
flag = false;
break;
}
}
if(flag == false) break;
if(i==gap) count++;//执行到最后i还会加一
temp++;
}
}
return count*gap;
}
public static void updateIdex(char[] chars,HashMap<Character, ArrayList<Integer>> record,boolean flag,int preIndex,int curIndex,int skip){
int gap = curIndex - preIndex;//重复的长度
int temp = skip/gap;//重复的次数
if(flag==true){
for(Entry<Character, ArrayList<Integer>> entry :record.entrySet()){
ArrayList<Integer> list = entry.getValue();
int i=0;
for(int a:list){
list.set(i, a+skip);
}
}
}else{
record.clear();
//int temp = skip/gap;
int start = (curIndex+(temp-1)*gap);
int end = start + gap -1;
for(int k=start;k<=end;k++){
addIdex(record,chars[k],k);
}
}
}
}
看我个人写的输入输出:
根据第一种情况,按照原答案只会输出,我要退款退款。因为原答案是,在每次进行跳过去重的时候,就之前存的索引文件,也就是record,给清空了,所以在跳过了“我要退款”后,到了索引位置8的“退”的时候,检查record发现为空,自然也就不会跳过“退款”了。所以在跳过之后,还需要保留跳过的字符串的索引(不管重复的有次,要最后一次重复的字符串的索引)。
根据第二种情况,不知道原答案运行后是不是也是对的,但本文代码能通过。也实现了数字不去重。
根据第三种情况,在于“我要退款我着急我要退款我着急”中,重复字符串为“我要退款我着急”,其中我是出现了两次的,所以record的数据结构必须为,一个字符可以对应多个索引。当到了索引位置为7的“我”时,需要和record中“我”的对应的两个索引位置0和4,都进行重复判断。
根据第四种情况,发现如果对应record中的字符如果有两个索引,那么从大往小依次进行判断,而且是判断有重复后,之后就不用进行判断了。
addIdex函数:对record添加该字符的索引。solve函数:对字符数组进行循环,如果有重复就跳过,没有重复就添加进result。是去重的主函数。
getCount函数:计算重复的长度,不管重复了几次。如果不重复,那么就返回0。先判断当前和之前,再判断当前和之后。
updateIdex函数:更新record。如果进入了if,也就是第三种情况,即record记录的字符串都是重复的,即solve函数的变量为j的for循环执行了最后一次循环体。如果进入了else,也就是第四种情况,即record记录的字符串一部分是重复的,那就直接清空,然后把最后一次重复的字符串添加进record。
个人总结:要注意循环体每次结束后,都会执行一遍i++,所以在循环体外判断i,要比在循环体内判断i,要多1!!