剑指offer-例题 第一次只出现一次的字符

题目描述:

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

我的解法:

import java.util.*;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str==null||str.length()==0)
            return -1;
        ArrayList<ListNode> result=new ArrayList<ListNode>();
        for(int i=0;i<str.length();i++)
        {
            int j;
            for(j=0;j<result.size();j++)
            {
                if(result.get(j).ch==str.charAt(i))
                {
                    result.get(j).num++;
                    break;//这里是个坑,一定要break
                }
            }
            if(j==result.size())
            {
                ListNode k=new ListNode(str.charAt(i),1,i);
                result.add(k);
            }
        }
        for(int i=0;i<result.size();i++)
        {
            if(result.get(i).num==1)
                return result.get(i).index;
        }
        return -1;
    }
}

class ListNode{
    char ch;
    int num;
    int index;
    
    public ListNode(char ch,int num,int index){
        this.ch=ch;
        this.num=num;
        this.index=index;
    }
}

要根据出现的先后顺序,就没办法将字符值转换为数组下标,那样就是按字符值大小排序了,为解决这一问题,方法如下:

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str==null||str.length()==0)
            return -1;
        int[] result=new int[100];
        int[] index=new int[100];
        for(int i=0;i<str.length();i++)
        {
            if(result[str.charAt(i)-'A']==0)
                index[str.charAt(i)-'A']=i;
            result[str.charAt(i)-'A']++;
        }
        for(int i=0;i<str.length();i++)
        {
            if(result[str.charAt(i)-'A']==1)//这里是个坑,这样才能保证是按出现顺序排列的而不是按字符大小顺序排列的
                return index[str.charAt(i)-'A'];
        }
        return -1;
    }
}

我的解法存在的问题:

1、时间复杂度为O(n*n)    还有提升的空间

2、为保证按出现顺序而不是按字符大小顺序,第二次应该在str上遍历而不是result上,而且这样还可以直接得到位置值

3、字符转换为数组下标,直接使用result[char]   相当于改变了数组中下标为  char对应ASCII值   的元素值

     这样也不需要在每次判断时都遍历一遍数组,节省时间

4、题目中只涉及到字母,一个字节就已足够,有2\wedge 8=256种情况,因此数组大小设为256,如果任意字符出现的话,char是2字节的数据类型

5、可以直接得到位置值,不需要通过另一个数组存储第一次出现的位置

正确解法:

时间复杂度:O(n)

空间复杂度:O(1)

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str==null||str.length()==0)
            return -1;
        int[] result=new int[256];
        for(int i=0;i<str.length();i++)
        {
            result[str.charAt(i)]++;
        }
        for(int i=0;i<str.length();i++)
        {
            if(result[str.charAt(i)]==1)
                return i;
        }
        return -1;
    }
}

每个字符根据其ASCII码值作为数组下标

 

相关题目:(哈希表的应用)

1、定义一个函数,输入两个字符串,从第一个字符串中删除在第二个字符串中出现过的所有字符。例如从第一个字符串"We are students. "中删除在第二个字符串"aeiou"中出现过的字符得到的结果是"W r Stdnts. "。

时间复杂度:O(n)

空间复杂度:O(1)

public String FirstNotRepeatingChar(String str1,String str2) {
		if(str1==null||str1.length()==0)
			return str1;
		if(str2==null||str2.length()==0)
			return str1;
		int[] num=new int[65536];
		for(int i=0;i<str2.length();i++)
			num[str2.charAt(i)]++;
		StringBuilder s=new StringBuilder(str1);
		for(int i=0;i<s.length();i++)
		{
			if(num[s.charAt(i)]!=0)
            {
                s.deleteCharAt(i);
                i--;//这是一个坑
            }	
		}
		return s.toString();
    }

2、定义一个函数,删除字符串中所有重复出现的字符。例如输入"google",删除重复的字符之后的结果是"gole"。

时间复杂度:O(n)

空间复杂度:O(1)

public String FirstNotRepeatingChar(String str1) {
		if(str1==null|str1.length()==0)
			return str1;
		StringBuilder s=new StringBuilder();
		int result[]=new int[65536];
		for(int i=0;i<str1.length();i++)
		{
			if(result[str1.charAt(i)]==0)
			{
				result[str1.charAt(i)]++;
				s.append(str1.charAt(i));
			}
		}
		return s.toString();
    }

下面是错误解法 :

s发生变化不利于此问题解决

public String FirstNotRepeatingChar(String str1) {
		if(str1==null|str1.length()==0)
			return str1;
		StringBuilder s=new StringBuilder(str1);
		int result[][]=new int[65536][2];
		for(int i=0;i<str1.length();i++)
		{
			if(result[str1.charAt(i)][0]==0)
			{
				result[str1.charAt(i)][1]=i;
			}
			result[str1.charAt(i)][0]++;
		}
        //这是一个坑,以下要全部在s上进行
		for(int i=0;i<s.length();i++)
		{
			if(result[s.charAt(i)][0]>1)
			{
				if(i!=result[s.charAt(i)][1])
				{
					s.deleteCharAt(i);
					i--;//这是一个坑,删除了长度发生变化,i也要跟着变化   但是i都已经发生变化了就不能判断它是否是第一次出现了
				}
					
			}
		}
		return s.toString();
    }

3、在英语中,如果两个单词中出现的字母相同,并且每个字母出现的次数也相同,那么这两个单词互为变位词。例如silent与listen、evil与live等互为变位词。请完成一个函数,判断输入的两个字符串是不是互为变位词。

时间复杂度:O(n)

空间复杂度:O(1)

public static boolean FirstNotRepeatingChar(String str1,String str2) {
		int[] s1=new int[65537];
		int[] s2=new int[65537];
		for(int i=0;i<str1.length();i++)
			s1[str1.charAt(i)]++;
		for(int i=0;i<str2.length();i++)
			s2[str2.charAt(i)]++;
		for(int i=0;i<str1.length();i++)
		{
			if(s1[str1.charAt(i)]!=s2[str1.charAt(i)])
				return false;
		}
		for(int i=0;i<str2.length();i++)
		{
			if(s2[str2.charAt(i)]!=s1[str2.charAt(i)])
				return false;
		}
		return true;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值