剑指offer 刷题日记-字符串类型题

基于字符的特性,0-256,他的哈希的方法主要是用数组的方式体现的0-256,或0-26,创建这样的数组来表述字符串的某种特性,这是字符串查找题目的一个特质

具体题目:

50题 找出字符串中找出第一个只出现一次的字符,比如输入“abacceff",则输出'b'

要想知道某个字符是不是只出现了一次,必须遍历字符串的每个字符。因此可以先遍历一次,统计每个字符出现次数。再遍历一次,遇到某个字符出现字符为1就立即返回。统计每个字符出现次数,可以用哈希表,不过如果输入中都是ASCII码,那么使用0-255表示即可。这样使用一个int[] count = new int[256]就能代替哈希表了,以count[someChar] = times这种方式表示某个字符出现的次数。比如‘a’的ASCII码是97,那么count[97]就表示了字符'a'的出现次数,以此类推。


java

package Chap5;

public class FirstAppearOnceChar {

    /**

    * 返回第一个不重复字符

    */

    public char firstNotRepeatingChar(String str) {

        if (str == null || str.length() == 0) return '\0';

        int[] count = new int[256];

        for (int i = 0; i < str.length(); i++) {

            count[str.charAt(i)]++;

        }

        for (int i = 0; i < str.length(); i++) {

            if (count[str.charAt(i)] == 1) return str.charAt(i);

        }

        return '\0';

    }

    /**

    * 返回第一个不重复字符在字符串中的索引

    */

    public int firstAppearOnceChar(String str) {

        if (str == null || str.length() == 0) return -1;

        int[] count = new int[256];

        for (int i = 0; i < str.length(); i++) {

            count[str.charAt(i)]++;

        }

        for (int i = 0; i < str.length(); i++) {

            if (count[str.charAt(i)] == 1) return i;

        }

        return -1;

    }

}

上面两个方法,一个是返回第一个只出现一次的字符,一个返回第一个只出现一个的字符的索引,思路都一样。根据count[someChar]获取某个字符的出现次数时间复杂度为O(1),对于长度为n的字符串,总的复杂度为O(n).


  48-字符流中第一个只出现一次的字符。

 这次字符串是动态变化的了,比如现在只从字符流中读取了两个字符为"go"那么字符流中第一个只出现一次的字符是'g',等到从字符流中读取了前6个字符"google"时,第一个只出现一次的字符变成了'l'.



使用一个insert函数模拟从字符流中读到一个字符。这次统计表`int[] occur = new int[256]`记录的是字符出现的索引.

-  如果某个字符出现过,那么`occur[someChar] >= 0`;

-  对于没有出现过的字符,令`occur[someChar] = -1`;

-  如果某个字符第二次出现,令`occur[someChar] = -2`。

要获得当前字符串中第一个只出现一次的,只需从所有`occur[someChar] >= 0`中结果中找出出现索引最小的那个字符即可。

如果第一次出现,将bt[ch]设置为index(字符出现的顺序),是大于0的,

如果重复出现了,就将bt[ch]设置为-1.

FirstAppearingOnce()的原理是,每次遍历数组,得到值大于0且index最小的那个位置i,再把i强转为char类型,就是要返回的字符

```java

public class Solution {

    int[] count = new int[256];

    int index=1;

    //Insert one char from stringstream

    public void Insert(char ch)

    {

        if(count[ch] == 0){

            count[ch]=index++;

        }else

            count[ch]= -1;

    }

  //return the first appearence once char in current stringstream

    public char FirstAppearingOnce()

    {

        int temp=Integer.MAX_VALUE;

        char ch='#';

        for(int i=0;i<256;i++){

            if(count[i]>0 && count[i]

剑指offer面试题49--最长不含重复字符串的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含'a'~'z'之间的字符,例如在字符串"arabcacfr"中,最长的不含重复字符的子字符串是"acfr",长度为4

动态规划,定义表示以第i个字符为结尾的不含重复字符的子字符串长度。

如果第i个字符之前没有出现过,则,比如‘abc',是必然的,然后字符’b‘之前没有出现过,则, 字符’c'之前没有出现过,那么,每次计算都会用到上一次计算的结果。

如果第i个字符之前出现过呢?找到该字符上次出现的位置preIndex,当前位置i - preIndex就得到这两个重复字符之间的距离,设为d。此时有两种情况

  • 如果d <= f(i-1),说明当前重复字符必然在f(i-1)所对应的字符串中,比如’bdcefgc‘,当前字符c前面出现过了,preIndex为2,此时d = 6 -2 = 4 ,小于f(i -1) = 7 (bdcefg)我们只好丢弃前一次出现的字符c及其前面的所有字符,得到当前最长不含重复字符的子字符串为’efgc‘,即f(i) = 4, 多举几个例子就知道,应该让f(i) = d

  • 如果d > f(i-1), 这说明当前重复字符必然在f(i-1)所对应的字符串之前,比如erabcdabr当前字符r和索引1处的r重复,preIndex =1, i = 8,d = 7。而f(i -1) = 4 (cdab),此时直接加1即可,即f(i) = f(i-1) +1


package Chap5;

public class LongestSubstring {

    public int findLongestSubstring(String str) {

        int curLen = 0;

        int maxLen = 0;

        // 0~25表示a~z,position[0] = index,表明a上次出现在index处

        int[] position = new int[26];

        for (int i = 0; i < 26; i++) {

            position[i] = -1;

        }

        for (int i = 0; i < str.length(); i++) {

            int preIndex = position[str.charAt(i) - 'a'];

            // 字符第一次出现,或者d > f(i -1)

            if (preIndex == -1 || i - preIndex > curLen) curLen++;

            // d <= f(i -1)

            else {

                if (curLen > maxLen) maxLen = curLen;

                curLen = i - preIndex;

            }

            // 记录当前字符出现的位置

            position[str.charAt(i) - 'a'] = i;

        }

        if (curLen > maxLen) maxLen = curLen;

        return maxLen;

    }

}

你可能感兴趣的:(剑指offer 刷题日记-字符串类型题)