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!!




posted @ 2018-05-10 09:25  allMayMight  阅读(132)  评论(0编辑  收藏  举报