如何加快首次唯一字符查找的速度

时间:2018-11-19 23:00:21

标签: java algorithm

我正在解决387. First Unique Character in a String LeetCode问题,定义为:

  

给出一个字符串,找到其中的第一个非重复字符并返回其索引。如果不存在,则返回-1。

     

示例:

s = "leetcode"
return 0.

s = "loveleetcode",
return 2.
     

注意:您可能会假设该字符串仅包含小写字母。

利用输入全为小写ASCII的优势,我创建了两个位向量来跟踪我们第一次和第二次遇到字符的时间。

下面的代码可以进一步改进吗? LeetCode说,下面的代码优于94.33%的解决方案。过去5.67%的解决方案还可以做些什么呢?

class Solution {

  public int firstUniqChar(String s) {
    int firstSpot = 0;
    int secondSpot = 0;
    char[] chars = s.toCharArray();

    for (char c : chars) {
      int mask = 1 << c - 'a';
      if ((firstSpot & mask) == 0) {
        firstSpot |= mask;
      } else if ((secondSpot & mask) == 0) {
        secondSpot |= mask;
      }
    }

    int i = 0;
    for (char c : chars) {
      int mask = 1 << c - 'a';
      if ((secondSpot & mask) == 0) {
         return i;
      }
      i++;
    }
    return -1;
  }

}

LeetCode score

是否有一些技巧可以提高LeetCode得分?增强的for-each循环似乎比标准的for循环性能更好,但我无法证明这一点,这是基于我以前提交的内容很少的观察结果。

3 个答案:

答案 0 :(得分:2)

我得到了 98.58 %:-

public int firstUniqChar(String s) {
    int count[] = new int[122 - 96];
    final char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        count[chars[i] - 97]++;
    }
    for (int i = 0; i < chars.length; i++) {
        if (count[chars[i] - 97] == 1)
            return i;
    }
    return -1;
}

enter image description here

答案 1 :(得分:1)

正如@Ruakh在评论中说的那样,leetcode产生的精确定时受到一定程度的随机性的影响,因此应谨慎对待。

  

我的印象是LeetCode正在做一个不科学的微基准测试,可能取决于随机因素。

仍然,可以通过摆脱测试来加快您的第一个循环的速度。以下循环在功能上等效;尽管它会更频繁地设置变量,但是更改局部整数变量的值要比测试是否需要更改花费的时间少:

for (char c : chars) {
  int mask = 1 << c - 'a';
  secondSpot |= mask & firstSpot;
  firstSpot |= mask;
}

(重要的是要按该顺序进行分配,这样,如果尚未看到该字符,第一个将不执行任何操作。)

答案 2 :(得分:1)

使用此:

import java.util.Arrays;

class Solution {
    //  0x60 < 'a' < 'z' < 0x80
    private final byte[] bCounter = new byte[0x80];
    private final int[] iCounter = new int[0x80];

    public int firstUniqChar(String s) {
        int len = s.length();
        if ((len & 0xff) == len) {
            Arrays.fill(bCounter, 0x60, 0x80, (byte)-1);
            for (int i = 0; i < len; i++)
                bCounter[s.charAt(i)]++;
            for (int i = 0; i < len; i++)
                if (bCounter[s.charAt(i)] == 0)
                    return i;
        } else {
            Arrays.fill(iCounter, 0x60, 0x80, -1);
            for (int i = 0; i < len; i++)
                iCounter[s.charAt(i)]++;
            for (int i = 0; i < len; i++)
                if (iCounter[s.charAt(i)] == 0)
                    return i;
        }
        return -1;
    }
}